From e984769a3be4e920b1ac54a93222ff4bc2896247 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Tue, 4 Jul 2023 10:39:55 +1000 Subject: [PATCH 01/51] Add Xlayered-tx-pool to the config log printout (#5665) Unrelated: clarify epoch length in javadoc Signed-off-by: Simon Dudley Co-authored-by: Gabriel Fukushima --- .../org/hyperledger/besu/cli/BesuCommand.java | 4 ++++ .../besu/cli/ConfigurationOverviewBuilder.java | 17 ++++++++++++++++- .../cli/ConfigurationOverviewBuilderTest.java | 16 ++++++++++++++-- .../besu/config/BftConfigOptions.java | 2 +- .../besu/config/CliqueConfigOptions.java | 2 +- 5 files changed, 36 insertions(+), 5 deletions(-) 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..330393a5bae 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -3675,6 +3675,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/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/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 */ From 6441d29f6ad9777417a0e0b20be5e3a8964aa827 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 4 Jul 2023 17:18:51 -0600 Subject: [PATCH 02/51] Add hooks to AbstractCreateOperation for library users (#5656) Add hooks for a successful contract create, a failed contract create, and an invalid contact create. Users of the library will be able to customize create responses without having to replace core logic. Signed-off-by: Danno Ferrin --- CHANGELOG.md | 2 + .../operation/AbstractCreateOperation.java | 44 +++- .../AbstractCreateOperationTest.java | 235 ++++++++++++++++++ 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 54a4ae5c926..87b5be8d08d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ + # Changelog ## 23.4.5 @@ -7,6 +8,7 @@ ### Additions and Improvements - 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) ### 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) 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..f3d04f772e7 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. */ @@ -185,18 +188,57 @@ private void complete(final MessageFrame frame, final MessageFrame childFrame, f 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/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..cccd5194878 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java @@ -0,0 +1,235 @@ +/* + * 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.ArrayDeque; +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 ArrayDeque messageFrameStack = new ArrayDeque<>(); + 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)) + .depth(1) + .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) + .worldUpdater(worldUpdater) + .build(); + 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(); + } +} From eaf5be2479047fc92ced254b867dd3d8597313bc Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 5 Jul 2023 08:21:53 -0600 Subject: [PATCH 03/51] Test updates for cancun execution-spec-tests (#5670) - support legacy V values (larger V value) and type 1+ (v is recId only) - new fields - shared transaction extraction - rejection detection Signed-off-by: Danno Ferrin --- ethereum/evmtool/build.gradle | 5 +- .../src/main/graal/reflection-config.json | 2 +- .../hyperledger/besu/evmtool/T8nExecutor.java | 161 +++++++++++++++++- .../besu/evmtool/T8nServerSubCommand.java | 103 +++-------- .../besu/evmtool/T8nSubCommand.java | 115 +------------ .../t8n/berlin-calculate-difficulty.json | 2 +- .../besu/evmtool/t8n/berlin-example-yul.json | 2 +- .../besu/evmtool/t8n/cancun-blobs-per-tx.json | 105 ++++++++++++ .../evmtool/t8n/istanbul-cumulative-gas.json | 2 +- .../evmtool/t8n/london-env-no-basefee.json | 2 +- .../besu/evmtool/t8n/shanghai-blockhash.json | 2 +- .../besu/evmtool/t8n/shanghai-init-code.json | 2 +- .../t8n/shanghai-withdrawals-no-nonce.json | 2 +- .../t8n/shanghai-withdrawals-overflow.json | 2 +- .../evmtool/t8n/shanghai-withdrawals.json | 2 +- .../referencetests/ReferenceTestEnv.java | 23 ++- .../ReferenceTestProtocolSchedules.java | 3 + 17 files changed, 325 insertions(+), 210 deletions(-) create mode 100644 ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json diff --git a/ethereum/evmtool/build.gradle b/ethereum/evmtool/build.gradle index 989c865412c..fa3f989cdd8 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -56,8 +56,6 @@ 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' @@ -67,6 +65,9 @@ dependencies { 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/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index 3b6da40c5c0..c3838237858 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -18,6 +18,9 @@ import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts; import org.hyperledger.besu.config.StubGenesisConfigOptions; +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.DataGas; import org.hyperledger.besu.datatypes.Hash; @@ -36,24 +39,33 @@ import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState; +import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evmtool.exception.UnsupportedForkException; +import org.hyperledger.besu.plugin.data.TransactionType; import java.io.IOException; +import java.io.PrintWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.NavigableMap; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.concurrent.TimeUnit; +import java.util.stream.StreamSupport; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -64,6 +76,149 @@ import org.apache.tuweni.units.bigints.UInt256; public class T8nExecutor { + + record RejectedTransaction(int index, String error) {} + + protected static 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(); + 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("maxFeePerDataGas")) { + builder.maxFeePerDataGas( + Wei.fromHexString(txNode.get("maxFeePerDataGas").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()) { + 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; + } + // FUTURE: placeholder code until 4844 PR merges + // 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 { + BigInteger v = + Bytes.fromHexStringLenient(txNode.get("v").textValue()).toUnsignedBigInteger(); + if (v.compareTo(BigInteger.valueOf(35)) >= 0) { + v = v.subtract(BigInteger.valueOf(35)).mod(BigInteger.TWO); + } else if (v.compareTo(BigInteger.valueOf(27)) >= 0) { + v = v.subtract(BigInteger.valueOf(27)).mod(BigInteger.TWO); + } + 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 +227,7 @@ static T8nResult runTest( final ReferenceTestEnv referenceTestEnv, final MutableWorldState initialWorldState, final List transactions, + final List rejections, final TracerManager tracerManager) { final ReferenceTestProtocolSchedules referenceTestProtocolSchedules = @@ -95,7 +251,7 @@ static T8nResult runTest( final Wei dataGasPrice = protocolSpec.getFeeMarket().dataPrice(DataGas.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; @@ -138,8 +294,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); 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..5bbf3199075 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,29 @@ */ package org.hyperledger.besu.evmtool; -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 static org.hyperledger.besu.evmtool.T8nExecutor.extractTransactions; + 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.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.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.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 picocli.CommandLine; @CommandLine.Command( @@ -69,6 +65,7 @@ public void run() { req -> req.bodyHandler( body -> { + ObjectMapper objectMapper = JsonUtils.createObjectMapper(); JsonObject t8nRequest = body.toJsonObject(); JsonObject state = t8nRequest.getJsonObject("state"); String fork = state.getString("fork"); @@ -81,18 +78,27 @@ public void run() { ReferenceTestWorldState initialWorldState = input.getJsonObject("alloc").mapTo(ReferenceTestWorldState.class); initialWorldState.persist(null); - List transactions = Collections.emptyList(); + List transactions = new ArrayList<>(); + List rejections = new ArrayList<>(); Object txs = input.getValue("txs"); if (txs != null) { if (txs instanceof JsonArray txsArray) { - transactions = extractTransactions(txsArray); + extractTransactions( + new PrintWriter(System.err, true, StandardCharsets.UTF_8), + txsArray.stream().map(s -> (JsonNode) s).iterator(), + transactions, + rejections); } else if (txs instanceof String tx) { transactions = - extractTransactions(new JsonArray().add(removeSurrounding("\"", tx))); + extractTransactions( + new PrintWriter(System.err, true, StandardCharsets.UTF_8), + List.of(new TextNode(removeSurrounding("\"", tx))) + .iterator(), + transactions, + rejections); } } - ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final T8nExecutor.T8nResult result = T8nExecutor.runTest( chainId, @@ -102,6 +108,7 @@ public void run() { referenceTestEnv, initialWorldState, transactions, + rejections, new T8nExecutor.TracerManager() { @Override public OperationTracer getManagedTracer( @@ -138,72 +145,6 @@ public void disposeTracer(final OperationTracer tracer) { 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()); - } - } - } - } - 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()); 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..dbf5a59756c 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,20 @@ 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 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 +41,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 +49,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 +66,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"); @@ -187,7 +172,8 @@ public void run() { 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 +215,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 +285,7 @@ public void disposeTracer(final OperationTracer tracer) { referenceTestEnv, initialWorldState, transactions, + rejections, tracerManager); try { @@ -340,96 +327,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/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-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..8ee3e7b21ad --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json @@ -0,0 +1,105 @@ +{ + "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": [], + "protected": true, + "maxFeePerDataGas": "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", + "currentExcessDataGas": "0", + "currentDataGasUsed": "0" + } + }, + "stdout": { + "alloc": { + "0x0000000000000000000000000000000000000200": { + "balance": "0x1" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "balance": "0x3b908bc7", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x43e39" + } + }, + "result": { + "stateRoot": "0xa6c91f68d20d3b6137ca1184a3995344256f0b53410b3577c9ab0a764a782cfb", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "rejected": [ + { + "index": 0, + "error": "Unsupported transaction type 3" + } + ], + "currentDifficulty": null, + "gasUsed": "0x0", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + } + } +} \ 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..d33e96bfd53 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 @@ -47,7 +47,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..3bf5beaae52 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 @@ -45,7 +45,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..046a9194cdf 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 @@ -41,7 +41,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c" }, 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..cc0d6d7d5c3 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.DataGas; 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,10 @@ Withdrawal asWithdrawal() { private final Map blockHashes; + private final String parentExcessDataGas; + + private final String parentDataGasUsed; + /** * Public constructor. * @@ -105,8 +108,14 @@ 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("currentExcessDataGas") final String currentExcessDataGas, + @JsonProperty("currentDataGasUsed") final String currentDataGasUsed, + @JsonProperty("parentExcessDataGas") final String parentExcessDataGas, + @JsonProperty("parentDataGasUsed") final String parentDataGasUsed) { super( generateTestBlockHash(previousHash, number), Hash.EMPTY_LIST_HASH, // ommersHash @@ -125,14 +134,16 @@ public ReferenceTestEnv( Optional.ofNullable(random).map(Difficulty::fromHexString).orElse(Difficulty.ZERO), 0L, null, // withdrawalsRoot + currentExcessDataGas == null ? null : DataGas.fromHexString(currentExcessDataGas), null, // depositsRoot - null, new MainnetBlockHeaderFunctions()); this.parentDifficulty = parentDifficulty; this.parentBaseFee = parentBaseFee; this.parentGasUsed = parentGasUsed; this.parentGasLimit = parentGasLimit; this.parentTimestamp = parentTimestamp; + this.parentExcessDataGas = parentExcessDataGas; + this.parentDataGasUsed = parentDataGasUsed; this.withdrawals = withdrawals == null ? List.of() @@ -217,6 +228,8 @@ public boolean equals(final Object o) { && Objects.equals(parentGasUsed, that.parentGasUsed) && Objects.equals(parentGasLimit, that.parentGasLimit) && Objects.equals(parentTimestamp, that.parentTimestamp) + && Objects.equals(parentDataGasUsed, that.parentDataGasUsed) + && Objects.equals(parentExcessDataGas, that.parentExcessDataGas) && Objects.equals(withdrawals, that.withdrawals); } @@ -229,6 +242,8 @@ public int hashCode() { parentGasUsed, parentGasLimit, parentTimestamp, + parentDataGasUsed, + parentExcessDataGas, withdrawals); } } 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..4f5a7d7b7c2 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,6 +74,9 @@ 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))); builder.put("Future_EIPs", createSchedule(genesisStub.clone().futureEipsTime(0))); builder.put("Experimental_EIPs", createSchedule(genesisStub.clone().experimentalEipsTime(0))); From 4b3853ff1f4c7b8968bcea72c441dd834cc7a61d Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 5 Jul 2023 12:27:52 -0600 Subject: [PATCH 04/51] Upgrade BouncyCastle libraries (#5675) Upgrade bouncy castle to v1.75. This involved a change in maven coordinates for other modules. Signed-off-by: Danno Ferrin --- crypto/algorithms/build.gradle | 2 +- enclave/build.gradle | 4 ++-- ethereum/api/build.gradle | 8 ++++---- ethereum/evmtool/build.gradle | 6 +++--- ethereum/trie/build.gradle | 2 +- ethereum/verkletrie/build.gradle | 2 +- gradle/verification-metadata.xml | 24 ++++++++++++++++++++++++ gradle/versions.gradle | 6 +++--- pki/build.gradle | 4 ++-- 9 files changed, 41 insertions(+), 17 deletions(-) diff --git a/crypto/algorithms/build.gradle b/crypto/algorithms/build.gradle index 3421c990bf3..ad5346e2273 100644 --- a/crypto/algorithms/build.gradle +++ b/crypto/algorithms/build.gradle @@ -29,7 +29,7 @@ jar { } dependencies { - api 'org.bouncycastle:bcprov-jdk15on' + api 'org.bouncycastle:bcprov-jdk18on' api 'org.slf4j:slf4j-api' implementation 'net.java.dev.jna:jna' diff --git a/enclave/build.gradle b/enclave/build.gradle index 302b2f246a4..103d7f1ab1f 100644 --- a/enclave/build.gradle +++ b/enclave/build.gradle @@ -9,7 +9,7 @@ dependencies { implementation 'io.vertx:vertx-web' implementation 'org.apache.tuweni:tuweni-net' - runtimeOnly('org.bouncycastle:bcpkix-jdk15on') + runtimeOnly('org.bouncycastle:bcpkix-jdk18on') // test dependencies. testImplementation project(':testutil') @@ -20,7 +20,7 @@ dependencies { // integration test dependencies. integrationTestImplementation project(':testutil') integrationTestImplementation 'org.assertj:assertj-core' - integrationTestImplementation 'org.bouncycastle:bcpkix-jdk15on' + integrationTestImplementation 'org.bouncycastle:bcpkix-jdk18on' integrationTestImplementation 'org.awaitility:awaitility' integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api' integrationTestImplementation 'org.mockito:mockito-core' diff --git a/ethereum/api/build.gradle b/ethereum/api/build.gradle index 68b53a3b76a..922dfd0ee6b 100644 --- a/ethereum/api/build.gradle +++ b/ethereum/api/build.gradle @@ -69,14 +69,14 @@ dependencies { implementation 'org.apache.tuweni:tuweni-toml' implementation 'org.apache.tuweni:tuweni-units' implementation 'org.antlr:antlr4-runtime' - implementation 'org.bouncycastle:bcprov-jdk15on' + implementation 'org.bouncycastle:bcprov-jdk18on' implementation 'org.springframework.security:spring-security-crypto' implementation 'org.xerial.snappy:snappy-java' annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" - runtimeOnly 'org.bouncycastle:bcpkix-jdk15on' + runtimeOnly 'org.bouncycastle:bcpkix-jdk18on' runtimeOnly 'io.netty:netty-transport-native-epoll' runtimeOnly 'io.netty:netty-transport-native-kqueue' @@ -106,7 +106,7 @@ dependencies { testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' - testSupportImplementation 'org.bouncycastle:bcpkix-jdk15on' + testSupportImplementation 'org.bouncycastle:bcpkix-jdk18on' integrationTestImplementation project(':config') integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') @@ -125,7 +125,7 @@ dependencies { artifacts { testSupportArtifacts testSupportJar } -task generateTestBlockchain() { +tasks.register('generateTestBlockchain') { def srcFiles = 'src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/trace/chain-data' def dataPath = "$buildDir/generated/data" def blocksBin = "$buildDir/resources/test/org/hyperledger/besu/ethereum/api/jsonrpc/trace/chain-data/blocks.bin" diff --git a/ethereum/evmtool/build.gradle b/ethereum/evmtool/build.gradle index fa3f989cdd8..df8b99aea53 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -102,7 +102,7 @@ tasks.register("dockerDistUntar") { } } -task distDocker(type: Exec) { +tasks.register('distDocker', Exec) { dependsOn dockerDistUntar def dockerBuildVersion = project.hasProperty('release.releaseVersion') ? project.property('release.releaseVersion') : "${rootProject.version}" def dockerOrgName = project.hasProperty('dockerOrgName') ? project.getProperty("dockerOrgName") : "hyperledger" @@ -124,9 +124,9 @@ task distDocker(type: Exec) { args "-c", "docker build --build-arg BUILD_DATE=${buildTime()} --build-arg VERSION=${dockerBuildVersion} --build-arg VCS_REF=${getCheckedOutGitCommitHash()} -t ${image} ." } -task dockerUpload(type: Exec) { +tasks.register('dockerUpload', Exec) { dependsOn distDocker - def dockerBuildVersion = project.hasProperty('release.releaseVersion') ? project.property('release.releaseVersion') : "${rootProject.version}" + String dockerBuildVersion = project.hasProperty('release.releaseVersion') ? project.property('release.releaseVersion') : "${rootProject.version}" def dockerOrgName = project.hasProperty('dockerOrgName') ? project.getProperty("dockerOrgName") : "hyperledger" def dockerArtifactName = project.hasProperty("dockerArtifactName") ? project.getProperty("dockerArtifactName") : "besu-evmtool" def imageName = "${dockerOrgName}/${dockerArtifactName}" diff --git a/ethereum/trie/build.gradle b/ethereum/trie/build.gradle index c671a75bf0f..0477841563d 100644 --- a/ethereum/trie/build.gradle +++ b/ethereum/trie/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'com.google.guava:guava' implementation 'io.opentelemetry:opentelemetry-api' implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.bouncycastle:bcprov-jdk15on' + implementation 'org.bouncycastle:bcprov-jdk18on' annotationProcessor 'org.immutables:value' diff --git a/ethereum/verkletrie/build.gradle b/ethereum/verkletrie/build.gradle index 0ca780ba88d..1d23538ed0c 100644 --- a/ethereum/verkletrie/build.gradle +++ b/ethereum/verkletrie/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-api' implementation 'org.apache.tuweni:tuweni-bytes' implementation 'org.apache.tuweni:tuweni-units' - implementation 'org.bouncycastle:bcprov-jdk15on' + implementation 'org.bouncycastle:bcprov-jdk18on' implementation 'org.hyperledger.besu:ipa-multipoint' annotationProcessor "org.immutables:value" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5d84c51d99d..a71f2bbff64 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -3545,6 +3545,14 @@ + + + + + + + + @@ -3569,6 +3577,14 @@ + + + + + + + + @@ -3585,6 +3601,14 @@ + + + + + + + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 88e87bdf01f..0c677809ad3 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -156,9 +156,9 @@ dependencyManagement { dependency 'org.awaitility:awaitility:4.2.0' - dependencySet(group: 'org.bouncycastle', version: '1.70') { - entry'bcpkix-jdk15on' - entry'bcprov-jdk15on' + dependencySet(group: 'org.bouncycastle', version: '1.75') { + entry'bcpkix-jdk18on' + entry'bcprov-jdk18on' } dependency 'org.fusesource.jansi:jansi:2.4.0' diff --git a/pki/build.gradle b/pki/build.gradle index a3edd47ce74..3eab6aca046 100644 --- a/pki/build.gradle +++ b/pki/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation 'com.google.guava:guava' implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.bouncycastle:bcpkix-jdk15on' + implementation 'org.bouncycastle:bcpkix-jdk18on' testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' @@ -43,7 +43,7 @@ dependencies { } configurations { testArtifacts } -task testJar(type: Jar) { +tasks.register('testJar', Jar) { archiveBaseName = "${project.name}-test" from sourceSets.test.output } From 6ac03af19ba2cd04f7fc86a52a7b767904fdcddf Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 7 Jul 2023 09:57:53 +0200 Subject: [PATCH 05/51] Introduce transaction validator interface (phase 1) (#5673) Signed-off-by: Fabio Di Fabio --- .../besu/services/BesuEventsImplTest.java | 4 +- .../merge/TransitionProtocolSchedule.java | 8 +- .../methods/EthGetTransactionReceiptTest.java | 2 + ...ndingPermissionTransactionFilterTest.java} | 4 +- .../BlockTransactionSelector.java | 31 ++--- ....java => PermissionTransactionFilter.java} | 6 +- .../mainnet/ClassicProtocolSpecs.java | 1 + .../mainnet/DefaultProtocolSchedule.java | 9 +- .../mainnet/MainnetProtocolSpecs.java | 1 + .../mainnet/MainnetTransactionProcessor.java | 6 +- .../mainnet/MainnetTransactionValidator.java | 55 ++------- .../PrivacySupportingProtocolSchedule.java | 4 +- .../besu/ethereum/mainnet/ProtocolSpec.java | 15 ++- .../ethereum/mainnet/ProtocolSpecBuilder.java | 22 ++-- .../mainnet/TransactionValidator.java | 65 ++++++++++ .../privacy/PrivateTransactionProcessor.java | 6 +- .../MainnetTransactionProcessorTest.java | 2 +- .../MainnetTransactionValidatorTest.java | 113 ++++++++++-------- .../eth/transactions/TransactionPool.java | 4 +- .../AbstractTransactionPoolTest.java | 4 +- ...actionsLayeredPendingTransactionsTest.java | 4 +- .../besu/ethereum/core/TransactionTest.java | 4 +- .../NoRewardProtocolScheduleWrapper.java | 9 +- 23 files changed, 217 insertions(+), 162 deletions(-) rename ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/{PendingTransactionFilterTest.java => PendingPermissionTransactionFilterTest.java} (98%) rename ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/{TransactionFilter.java => PermissionTransactionFilter.java} (88%) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java 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..68170f3258c 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -48,9 +48,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.TransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; @@ -99,7 +99,7 @@ public class BesuEventsImplTest { @Mock private EthContext mockEthContext; @Mock private EthMessages mockEthMessages; @Mock private EthScheduler mockEthScheduler; - @Mock private MainnetTransactionValidator mockTransactionValidator; + @Mock private TransactionValidator mockTransactionValidator; @Mock private ProtocolSpec mockProtocolSpec; @Mock private WorldStateArchive mockWorldStateArchive; @Mock private MutableWorldState mockWorldState; 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..0b2a2f5a372 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; @@ -216,12 +216,12 @@ 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 setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter) { transitionUtils.dispatchConsumerAccordingToMergeState( - protocolSchedule -> protocolSchedule.setTransactionFilter(transactionFilter)); + protocolSchedule -> protocolSchedule.setTransactionFilter(permissionTransactionFilter)); } /** 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..8ea908e5889 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 @@ -115,6 +115,7 @@ public class EthGetTransactionReceiptTest { null, Optional.empty(), null, + true, true); private final ProtocolSpec statusTransactionTypeSpec = new ProtocolSpec( @@ -144,6 +145,7 @@ public class EthGetTransactionReceiptTest { null, Optional.empty(), null, + true, true); @SuppressWarnings("unchecked") 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 98% 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..64db24b674a 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 @@ -45,7 +45,7 @@ import org.junit.runners.Parameterized; @RunWith(Parameterized.class) -public class PendingTransactionFilterTest { +public class PendingPermissionTransactionFilterTest { @Parameterized.Parameters public static Collection data() { @@ -97,7 +97,7 @@ public static Collection data() { private final int limit; private final List expectedListOfTransactionHash; - public PendingTransactionFilterTest( + public PendingPermissionTransactionFilterTest( final List filters, final int limit, final List expectedListOfTransactionHash) { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 88a2fc4573d..e4701f848ec 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -78,15 +79,12 @@ */ public class BlockTransactionSelector { - public record TransactionValidationResult( - Transaction transaction, ValidationResult validationResult) {} - public static class TransactionSelectionResults { private final List transactions = Lists.newArrayList(); private final Map> transactionsByType = new EnumMap<>(TransactionType.class); private final List receipts = Lists.newArrayList(); - private final List invalidTransactions = Lists.newArrayList(); + private final Map invalidTransactions = new HashMap<>(); private final List selectionResults = Lists.newArrayList(); private long cumulativeGasUsed = 0; private long cumulativeDataGasUsed = 0; @@ -114,9 +112,8 @@ private void update( } private void updateWithInvalidTransaction( - final Transaction transaction, - final ValidationResult validationResult) { - invalidTransactions.add(new TransactionValidationResult(transaction, validationResult)); + final Transaction transaction, final TransactionInvalidReason invalidReason) { + invalidTransactions.put(transaction, invalidReason); } public List getTransactions() { @@ -139,7 +136,7 @@ public long getCumulativeDataGasUsed() { return cumulativeDataGasUsed; } - public List getInvalidTransactions() { + public Map getInvalidTransactions() { return invalidTransactions; } @@ -278,7 +275,7 @@ public TransactionSelectionResults buildTransactionListForBlock() { .log(); pendingTransactions.selectTransactions( pendingTransaction -> { - final var res = evaluateTransaction(pendingTransaction, false); + final var res = evaluateTransaction(pendingTransaction); transactionSelectionResults.addSelectionResult(res); return res; }); @@ -298,7 +295,7 @@ public TransactionSelectionResults buildTransactionListForBlock() { public TransactionSelectionResults evaluateTransactions(final List transactions) { transactions.forEach( transaction -> - transactionSelectionResults.addSelectionResult(evaluateTransaction(transaction, true))); + transactionSelectionResults.addSelectionResult(evaluateTransaction(transaction))); return transactionSelectionResults; } @@ -311,8 +308,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."); } @@ -393,12 +389,9 @@ private TransactionSelectionResult evaluateTransaction( } return txSelectionResult; } else { + transactionSelectionResults.updateWithInvalidTransaction( + transaction, effectiveResult.getValidationResult().getInvalidReason()); - final boolean isIncorrectNonce = isIncorrectNonce(effectiveResult.getValidationResult()); - if (!isIncorrectNonce || reportFutureNonceTransactionsAsInvalid) { - transactionSelectionResults.updateWithInvalidTransaction( - transaction, effectiveResult.getValidationResult()); - } return transactionSelectionResultForInvalidResult( transaction, effectiveResult.getValidationResult()); } @@ -472,10 +465,6 @@ 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()); 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/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index bb99bd72390..4aa97733f9c 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 @@ -72,6 +72,7 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( final EvmConfiguration evmConfiguration) { return MainnetProtocolSpecs.homesteadDefinition( contractSizeLimit, configStackSizeLimit, evmConfiguration) + .isReplayProtectionSupported(true) .gasCalculator(TangerineWhistleGasCalculator::new) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> 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..b2cdc9ac06c 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; @@ -111,9 +111,12 @@ public boolean anyMatch(final Predicate predicate) { } @Override - public void setTransactionFilter(final TransactionFilter transactionFilter) { + public void setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter) { protocolSpecs.forEach( - spec -> spec.spec().getTransactionValidator().setTransactionFilter(transactionFilter)); + spec -> + spec.spec() + .getTransactionValidator() + .setPermissionTransactionFilter(permissionTransactionFilter)); } @Override 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..e5b7a032bae 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 @@ -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( 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..407c6850daf 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 @@ -64,7 +64,7 @@ public class MainnetTransactionProcessor { protected final GasCalculator gasCalculator; - protected final MainnetTransactionValidator transactionValidator; + protected final TransactionValidator transactionValidator; private final AbstractMessageProcessor contractCreationProcessor; @@ -81,7 +81,7 @@ public class MainnetTransactionProcessor { public MainnetTransactionProcessor( final GasCalculator gasCalculator, - final MainnetTransactionValidator transactionValidator, + final TransactionValidator transactionValidator, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final boolean clearEmptyAccounts, @@ -498,7 +498,7 @@ public TransactionProcessingResult processTransaction( } } - public MainnetTransactionValidator getTransactionValidator() { + public TransactionValidator getTransactionValidator() { return transactionValidator; } 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..710e24601fd 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 @@ -21,8 +21,8 @@ import org.hyperledger.besu.datatypes.Hash; 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.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.evm.account.Account; @@ -39,7 +39,7 @@ *

The {@link MainnetTransactionValidator} performs the intrinsic gas cost check on the given * {@link Transaction}. */ -public class MainnetTransactionValidator { +public class MainnetTransactionValidator implements TransactionValidator { private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; @@ -49,7 +49,7 @@ public class MainnetTransactionValidator { private final Optional chainId; - private Optional transactionFilter = Optional.empty(); + private Optional permissionTransactionFilter = Optional.empty(); private final Set acceptedTransactionTypes; private final int maxInitcodeSize; @@ -100,16 +100,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, @@ -199,6 +190,7 @@ private ValidationResult validateCostAndFee( return ValidationResult.valid(); } + @Override public ValidationResult validateForSender( final Transaction transaction, final Account sender, @@ -256,11 +248,7 @@ public ValidationResult validateForSender( 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))) { @@ -302,7 +290,7 @@ public ValidationResult validateTransactionSignature( private boolean isSenderAllowed( final Transaction transaction, final TransactionValidationParams validationParams) { if (validationParams.checkLocalPermissions() || validationParams.checkOnchainPermissions()) { - return transactionFilter + return permissionTransactionFilter .map( c -> c.permitted( @@ -315,30 +303,9 @@ private boolean isSenderAllowed( } } - public void setTransactionFilter(final TransactionFilter transactionFilter) { - this.transactionFilter = Optional.of(transactionFilter); - } - - /** - * 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); + @Override + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { + this.permissionTransactionFilter = Optional.of(permissionTransactionFilter); } } 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..aed9a52f7b9 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,12 @@ 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 setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter); void setPublicWorldStateArchiveForPrivacyBlockProcessor( final WorldStateArchive publicWorldStateArchive); 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..8805ad556e0 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 TransactionValidator transactionValidator; private final MainnetTransactionProcessor transactionProcessor; @@ -81,6 +81,7 @@ public class ProtocolSpec { private final DepositsValidator depositsValidator; private final boolean isPoS; + private final boolean isReplayProtectionSupported; /** * Creates a new protocol specification instance. * @@ -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 TransactionValidator transactionValidator, final MainnetTransactionProcessor transactionProcessor, final PrivateTransactionProcessor privateTransactionProcessor, final BlockHeaderValidator blockHeaderValidator, @@ -139,7 +142,8 @@ 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; @@ -167,6 +171,7 @@ public ProtocolSpec( this.withdrawalsProcessor = withdrawalsProcessor; this.depositsValidator = depositsValidator; this.isPoS = isPoS; + this.isReplayProtectionSupported = isReplayProtectionSupported; } /** @@ -183,12 +188,12 @@ public String getName() { * * @return the transaction validator */ - public MainnetTransactionValidator getTransactionValidator() { + public TransactionValidator getTransactionValidator() { return transactionValidator; } 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..60787068dbb 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 @@ -53,7 +53,7 @@ public class ProtocolSpecBuilder { private DifficultyCalculator difficultyCalculator; private EvmConfiguration evmConfiguration; private BiFunction evmBuilder; - private BiFunction + private BiFunction transactionValidatorBuilder; private Function blockHeaderValidatorBuilder; private Function ommerHeaderValidatorBuilder; @@ -81,6 +81,7 @@ 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; @@ -125,7 +126,7 @@ public ProtocolSpecBuilder evmBuilder( } public ProtocolSpecBuilder transactionValidatorBuilder( - final BiFunction + final BiFunction transactionValidatorBuilder) { this.transactionValidatorBuilder = transactionValidatorBuilder; return this; @@ -270,6 +271,12 @@ 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"); @@ -302,7 +309,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { final EVM evm = evmBuilder.apply(gasCalculator, evmConfiguration); final PrecompiledContractConfiguration precompiledContractConfiguration = new PrecompiledContractConfiguration(gasCalculator, privacyParameters); - final MainnetTransactionValidator transactionValidator = + final TransactionValidator transactionValidator = transactionValidatorBuilder.apply(gasCalculator, gasLimitCalculator); final AbstractMessageProcessor contractCreationProcessor = contractCreationProcessorBuilder.apply(gasCalculator, evm); @@ -374,11 +381,12 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { withdrawalsValidator, Optional.ofNullable(withdrawalsProcessor), depositsValidator, - isPoS); + isPoS, + isReplayProtectionSupported); } private PrivateTransactionProcessor createPrivateTransactionProcessor( - final MainnetTransactionValidator transactionValidator, + final TransactionValidator transactionValidator, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final PrecompileContractRegistry precompileContractRegistry) { @@ -435,14 +443,14 @@ private BlockHeaderValidator createBlockHeaderValidator( public interface TransactionProcessorBuilder { MainnetTransactionProcessor apply( GasCalculator gasCalculator, - MainnetTransactionValidator transactionValidator, + TransactionValidator transactionValidator, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor); } public interface PrivateTransactionProcessorBuilder { PrivateTransactionProcessor apply( - MainnetTransactionValidator transactionValidator, + TransactionValidator transactionValidator, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor, PrivateTransactionValidator privateTransactionValidator); 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..81514f0edde --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.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.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; + +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); + + /** + * Set the permission transaction filter. This way of setting the filter is deprecated and will be + * removed. + * + * @param permissionTransactionFilter the permission transaction filter + */ + @Deprecated + void setPermissionTransactionFilter(PermissionTransactionFilter permissionTransactionFilter); +} 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..fdbeb19bf70 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.TransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -49,7 +49,7 @@ public class PrivateTransactionProcessor { private static final Logger LOG = LoggerFactory.getLogger(PrivateTransactionProcessor.class); @SuppressWarnings("unused") - private final MainnetTransactionValidator transactionValidator; + private final TransactionValidator transactionValidator; private final PrivateTransactionValidator privateTransactionValidator; @@ -63,7 +63,7 @@ public class PrivateTransactionProcessor { private final boolean clearEmptyAccounts; public PrivateTransactionProcessor( - final MainnetTransactionValidator transactionValidator, + final TransactionValidator transactionValidator, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final boolean clearEmptyAccounts, 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..508448bc4ab 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 @@ -53,7 +53,7 @@ public class MainnetTransactionProcessorTest { private static final int MAX_STACK_SIZE = 1024; private final GasCalculator gasCalculator = new LondonGasCalculator(); - @Mock private MainnetTransactionValidator transactionValidator; + @Mock private TransactionValidator transactionValidator; @Mock private AbstractMessageProcessor contractCreationProcessor; @Mock private AbstractMessageProcessor messageCallProcessor; 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..672b93c5edf 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 @@ -15,6 +15,8 @@ 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; @@ -33,8 +35,8 @@ import org.hyperledger.besu.datatypes.Hash; 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.TransactionFilter; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -63,7 +65,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; @@ -74,7 +76,7 @@ public class MainnetTransactionValidatorTest { @Test public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); final Transaction transaction = @@ -91,7 +93,7 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { @Test public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) @@ -102,7 +104,7 @@ public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot( @Test public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -114,51 +116,51 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { @Test public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( 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 = + final TransactionValidator validator = new MainnetTransactionValidator( 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 = + final TransactionValidator validator = new MainnetTransactionValidator( 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 = + final TransactionValidator validator = new MainnetTransactionValidator( 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 = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); @@ -166,13 +168,13 @@ public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { 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 = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); @@ -181,16 +183,18 @@ 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 = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(false)); + validator.setPermissionTransactionFilter(transactionFilter(false)); Account invalidEOA = when(account(basicTransaction.getUpfrontCost(0L), basicTransaction.getNonce()) @@ -198,38 +202,42 @@ public void shouldRejectTransactionIfAccountIsNotEOA() { .thenReturn(Hash.fromHexStringLenient("0xdeadbeef")) .getMock(); - assertThat(validator.validateForSender(basicTransaction, invalidEOA, true)) + assertThat(validator.validateForSender(basicTransaction, invalidEOA, transactionPoolParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); } @Test public void shouldRejectTransactionIfAccountIsNotPermitted() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(false)); + validator.setPermissionTransactionFilter(transactionFilter(false)); - assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) + assertThat( + validator.validateForSender( + basicTransaction, accountWithNonce(0), transactionPoolParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); } @Test public void shouldAcceptValidTransactionIfAccountIsPermitted() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(true)); + validator.setPermissionTransactionFilter(transactionFilter(true)); - assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) + assertThat( + validator.validateForSender( + basicTransaction, accountWithNonce(0), transactionPoolParams)) .isEqualTo(ValidationResult.valid()); } @Test public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter(true)); + validator.setPermissionTransactionFilter(transactionFilter(true)); assertThat( validator.validateForSender( @@ -245,13 +253,13 @@ 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 = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -263,7 +271,7 @@ public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 }), Integer.MAX_VALUE); - validator.setTransactionFilter(transactionFilter(true)); + validator.setPermissionTransactionFilter(transactionFilter(true)); final Transaction transaction = Transaction.builder() @@ -292,17 +300,18 @@ public void shouldPropagateCorrectStateChangeParamToTransactionFilter() { ArgumentCaptor.forClass(Boolean.class); final ArgumentCaptor stateChangeOnchainParamCaptor = ArgumentCaptor.forClass(Boolean.class); - final TransactionFilter transactionFilter = mock(TransactionFilter.class); - when(transactionFilter.permitted( + final PermissionTransactionFilter permissionTransactionFilter = + mock(PermissionTransactionFilter.class); + when(permissionTransactionFilter.permitted( any(Transaction.class), stateChangeLocalParamCaptor.capture(), stateChangeOnchainParamCaptor.capture())) .thenReturn(true); - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter); + validator.setPermissionTransactionFilter(permissionTransactionFilter); final TransactionValidationParams validationParams = ImmutableTransactionValidationParams.builder().checkOnchainPermissions(true).build(); @@ -315,12 +324,13 @@ public void shouldPropagateCorrectStateChangeParamToTransactionFilter() { @Test public void shouldNotCheckAccountPermissionIfBothValidationParamsCheckPermissionsAreFalse() { - final TransactionFilter transactionFilter = mock(TransactionFilter.class); + final PermissionTransactionFilter permissionTransactionFilter = + mock(PermissionTransactionFilter.class); - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setTransactionFilter(transactionFilter); + validator.setPermissionTransactionFilter(permissionTransactionFilter); final TransactionValidationParams validationParams = ImmutableTransactionValidationParams.builder() @@ -333,12 +343,12 @@ public void shouldNotCheckAccountPermissionIfBothValidationParamsCheckPermission assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), validationParams)) .isEqualTo(ValidationResult.valid()); - verifyNoInteractions(transactionFilter); + verifyNoInteractions(permissionTransactionFilter); } @Test public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { - final MainnetTransactionValidator frontierValidator = + final TransactionValidator frontierValidator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -348,7 +358,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { Set.of(TransactionType.FRONTIER), Integer.MAX_VALUE); - final MainnetTransactionValidator eip1559Validator = + final TransactionValidator eip1559Validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -381,7 +391,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { @Test public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -405,7 +415,7 @@ public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { @Test public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { final Optional zeroBaseFee = Optional.of(Wei.ZERO); - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -428,7 +438,7 @@ public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { @Test public void shouldAcceptValidEIP1559() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -453,7 +463,7 @@ public void shouldAcceptValidEIP1559() { @Test public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransactionPool() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -479,7 +489,7 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction @Test public void shouldRejectTooLargeInitcode() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -506,7 +516,7 @@ public void shouldRejectTooLargeInitcode() { @Test public void shouldAcceptTransactionWithAtLeastOneBlob() { - final MainnetTransactionValidator validator = + final TransactionValidator validator = new MainnetTransactionValidator( gasCalculator, GasLimitCalculator.constant(), @@ -538,10 +548,11 @@ private Account account(final Wei balance, final long nonce) { return account; } - private TransactionFilter transactionFilter(final boolean permitted) { - final TransactionFilter transactionFilter = mock(TransactionFilter.class); - when(transactionFilter.permitted(any(Transaction.class), anyBoolean(), anyBoolean())) + private PermissionTransactionFilter transactionFilter(final boolean permitted) { + final PermissionTransactionFilter permissionTransactionFilter = + mock(PermissionTransactionFilter.class); + when(permissionTransactionFilter.permitted(any(Transaction.class), anyBoolean(), anyBoolean())) .thenReturn(permitted); - return transactionFilter; + return permissionTransactionFilter; } } 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..0d2f58220f9 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 @@ -30,9 +30,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; @@ -353,7 +353,7 @@ private static void logReAddedTransactions( .log(); } - private MainnetTransactionValidator getTransactionValidator() { + private TransactionValidator getTransactionValidator() { return protocolSchedule .getByBlockHeader(protocolContext.getBlockchain().getChainHeadHeader()) .getTransactionValidator(); 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..5b4a11f441d 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.TransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -97,7 +97,7 @@ public abstract class AbstractTransactionPoolTest { private static final KeyPair KEY_PAIR2 = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - @Mock protected MainnetTransactionValidator transactionValidator; + @Mock protected TransactionValidator transactionValidator; @Mock protected PendingTransactionAddedListener listener; @Mock protected MiningParameters miningParameters; @Mock protected TransactionsMessageSender transactionsMessageSender; 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..b10b4dcf7c5 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.TransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -93,7 +93,7 @@ public abstract class AbstractTransactionsLayeredPendingTransactionsTest { private static final KeyPair KEY_PAIR2 = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - @Mock protected MainnetTransactionValidator transactionValidator; + @Mock protected TransactionValidator transactionValidator; @Mock protected PendingTransactionAddedListener listener; @Mock protected MiningParameters miningParameters; @Mock protected TransactionsMessageSender transactionsMessageSender; 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..fd595cfb158 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,7 +50,7 @@ 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()) 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..a4f27328f9c 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; @@ -86,7 +86,8 @@ public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { original.getWithdrawalsValidator(), original.getWithdrawalsProcessor(), original.getDepositsValidator(), - original.isPoS()); + original.isPoS(), + original.isReplayProtectionSupported()); } @Override @@ -120,8 +121,8 @@ public String listMilestones() { } @Override - public void setTransactionFilter(final TransactionFilter transactionFilter) { - delegate.setTransactionFilter(transactionFilter); + public void setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter) { + delegate.setTransactionFilter(permissionTransactionFilter); } @Override From 3f2a0160a8a16c988bd939b36d30285cc680465a Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Tue, 11 Jul 2023 08:59:14 +0100 Subject: [PATCH 06/51] Only validate `--miner-enabled` option for ethash networks (#5669) * Modify the min-gas-price option validation * Check for whether ethash is in use, either from genesis or network config, and use that for miner checks * Add genesis configuration isPoa() convenience function --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead Co-authored-by: Simon Dudley Signed-off-by: Simon Dudley --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 23 ++--- .../hyperledger/besu/cli/BesuCommandTest.java | 85 ++++++++++++++++++- .../besu/config/GenesisConfigOptions.java | 7 ++ .../besu/config/JsonGenesisConfigOptions.java | 5 ++ .../besu/config/StubGenesisConfigOptions.java | 5 ++ .../besu/config/GenesisConfigOptionsTest.java | 11 +++ 7 files changed, 124 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b5be8d08d..797ab5f5e93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - 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) ### Download Links 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 330393a5bae..831c52a74f4 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -2133,7 +2133,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 +2144,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, 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..7e634282260 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -168,6 +168,20 @@ public class BesuCommandTest extends CommandTestAbstract { (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 +3698,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 +3712,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 +3767,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 +3855,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"); 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 41f385fc4f5..ba1f52769e8 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. * 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 f9cf0696290..ab269142ba2 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; 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 949205e9b04..a0eac55cd8a 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -116,6 +116,11 @@ public boolean isQbft() { return false; } + @Override + public boolean isPoa() { + return false; + } + @Override public CheckpointConfigOptions getCheckpointOptions() { return CheckpointConfigOptions.DEFAULT; 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..d04027dcc10 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(); } From 901661cb4ff1c390e84e705254d07ef5a295fb76 Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Tue, 11 Jul 2023 22:26:32 -0700 Subject: [PATCH 07/51] Update tuweni2.4.2 (#5684) * Revert "Revert "Update Tuweni to 2.4.1 (#5513)" (#5585)" This reverts commit 6111e1bbc36f6b8b19780412cc61f849b639e350. Signed-off-by: Antoine Toulme * update Tuweni to 2.4.2 Signed-off-by: Antoine Toulme --------- Signed-off-by: Antoine Toulme --- CHANGELOG.md | 1 + acceptance-tests/dsl/build.gradle | 6 +- acceptance-tests/tests/build.gradle | 2 +- besu/build.gradle | 12 +- config/build.gradle | 4 +- consensus/clique/build.gradle | 4 +- consensus/common/build.gradle | 2 +- consensus/ibft/build.gradle | 4 +- consensus/merge/build.gradle | 4 +- consensus/qbft/build.gradle | 4 +- crypto/algorithms/build.gradle | 4 +- datatypes/build.gradle | 4 +- enclave/build.gradle | 2 +- ethereum/api/build.gradle | 8 +- ethereum/blockcreation/build.gradle | 4 +- ethereum/core/build.gradle | 14 +- .../ethereum/core/TransactionTestFixture.java | 3 +- .../core/encoding/WithdrawalEncoderTest.java | 3 +- ethereum/eth/build.gradle | 6 +- .../eth/sync/snapsync/RangeManagerTest.java | 4 +- .../layered/BaseTransactionPoolTest.java | 2 +- ethereum/ethstats/build.gradle | 2 +- ethereum/mock-p2p/build.gradle | 2 +- ethereum/p2p/build.gradle | 14 +- .../p2p/network/DefaultP2PNetwork.java | 12 +- .../p2p/network/DefaultP2PNetworkTest.java | 17 +- ethereum/permissioning/build.gradle | 6 +- ethereum/referencetests/build.gradle | 4 +- ethereum/retesteth/build.gradle | 4 +- ethereum/rlp/build.gradle | 4 +- ethereum/stratum/build.gradle | 4 +- ethereum/trie/build.gradle | 4 +- ethereum/verkletrie/build.gradle | 6 +- evm/build.gradle | 4 +- gradle/verification-metadata.xml | 400 ++++++++++++++++++ gradle/versions.gradle | 9 +- pki/build.gradle | 2 +- plugin-api/build.gradle | 4 +- plugins/rocksdb/build.gradle | 2 +- privacy-contracts/build.gradle | 6 +- services/tasks/build.gradle | 2 +- testutil/build.gradle | 6 +- 42 files changed, 513 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 797ab5f5e93..a47fb3cd942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - 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) ### 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) 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/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/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/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/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/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/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/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/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/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/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/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..79accd5c5e1 100644 --- a/ethereum/api/build.gradle +++ b/ethereum/api/build.gradle @@ -64,10 +64,10 @@ 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' diff --git a/ethereum/blockcreation/build.gradle b/ethereum/blockcreation/build.gradle index 6ab57e51315..d813869db6a 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') diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 2804b2648d0..4f2db3119d7 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -54,10 +54,10 @@ 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' @@ -78,9 +78,9 @@ dependencies { 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' 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..79307d2ebdc 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 @@ -32,7 +32,8 @@ public class TransactionTestFixture { private static final Hash DEFAULT_VERSIONED_HASH = Hash.wrap( Bytes32.wrap( - Bytes.concatenate(Bytes.fromHexString("0x01"), Bytes.repeat((byte) 42, 31)))); + Bytes.concatenate( + Bytes.fromHexString("0x01"), Bytes.fromHexString("2a".repeat(31))))); private TransactionType transactionType = TransactionType.FRONTIER; 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/eth/build.gradle b/ethereum/eth/build.gradle index 0f68fc521d3..68a40750b7c 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" 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..e4e116b8a8c 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 @@ -41,7 +41,7 @@ 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/transactions/layered/BaseTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java index defafb1b369..b594d7a258b 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 @@ -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/ethstats/build.gradle b/ethereum/ethstats/build.gradle index c361c16c860..52fe38473ce 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') diff --git a/ethereum/mock-p2p/build.gradle b/ethereum/mock-p2p/build.gradle index b73c0a051fd..bfab38e98c7 100644 --- a/ethereum/mock-p2p/build.gradle +++ b/ethereum/mock-p2p/build.gradle @@ -35,7 +35,7 @@ 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' diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 6d36dfd1c74..0775a51d2a9 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -45,17 +45,17 @@ 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' 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/network/DefaultP2PNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java index ffc1c84431b..00cbccb126a 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,6 +58,9 @@ 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; @@ -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/permissioning/build.gradle b/ethereum/permissioning/build.gradle index 5b10e216ecf..a0493360a15 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') diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 49dc6109074..1aa1e2a2651 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' diff --git a/ethereum/retesteth/build.gradle b/ethereum/retesteth/build.gradle index 08d06932905..5bb9b1d8559 100644 --- a/ethereum/retesteth/build.gradle +++ b/ethereum/retesteth/build.gradle @@ -47,8 +47,8 @@ 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' diff --git a/ethereum/rlp/build.gradle b/ethereum/rlp/build.gradle index 678918d7cef..17303480e92 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' 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..99f44680d92 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' @@ -46,7 +46,7 @@ dependencies { 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' diff --git a/ethereum/verkletrie/build.gradle b/ethereum/verkletrie/build.gradle index 1d23538ed0c..642318e25c7 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' @@ -48,7 +48,7 @@ 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' 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/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a71f2bbff64..c9a2105d52d 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 @@ + + + + + + + + @@ -4526,6 +4875,14 @@ + + + + + + + + @@ -4563,11 +4920,24 @@ + + + + + + + + + + + + + @@ -4576,6 +4946,14 @@ + + + + + + + + @@ -4587,6 +4965,17 @@ + + + + + + + + + + + @@ -4598,6 +4987,17 @@ + + + + + + + + + + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 0c677809ad3..4089bbb3014 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' 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..eef486e6c7b 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -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') } diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index fa4b0e9f0e0..95e9b5087a3 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -45,7 +45,7 @@ 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') 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/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' From 86b2b600a05daeee2e4f847134b8aa9e928453b0 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 13 Jul 2023 13:39:52 +0200 Subject: [PATCH 08/51] Do not leak references to PendingTransactions (#5693) Signed-off-by: Fabio Di Fabio --- .../CliqueBesuControllerBuilder.java | 2 +- .../controller/IbftBesuControllerBuilder.java | 4 +- .../MainnetBesuControllerBuilder.java | 2 +- .../MergeBesuControllerBuilder.java | 2 +- .../controller/QbftBesuControllerBuilder.java | 4 +- .../blockcreation/CliqueBlockCreator.java | 8 +- .../blockcreation/CliqueMinerExecutor.java | 10 +- .../blockcreation/CliqueBlockCreatorTest.java | 49 ++- .../CliqueMinerExecutorTest.java | 64 ++- .../bft/blockcreation/BftBlockCreator.java | 8 +- .../blockcreation/BftBlockCreatorFactory.java | 12 +- .../ibft/support/TestContextBuilder.java | 33 +- .../blockcreation/BftBlockCreatorTest.java | 30 +- .../blockcreation/MergeBlockCreator.java | 8 +- .../merge/blockcreation/MergeCoordinator.java | 8 +- .../blockcreation/MergeCoordinatorTest.java | 47 ++- .../merge/blockcreation/MergeReorgTest.java | 6 +- .../qbft/support/TestContextBuilder.java | 107 ++--- .../QbftBlockCreatorFactory.java | 8 +- .../QbftBlockCreatorFactoryTest.java | 4 +- .../api/graphql/GraphQLDataFetchers.java | 2 +- .../pojoadapter/PendingStateAdapter.java | 12 +- .../api/jsonrpc/LatestNonceProvider.java | 10 +- .../methods/EthGetTransactionByHash.java | 10 +- .../methods/EthGetTransactionCount.java | 15 +- .../TxPoolBesuPendingTransactions.java | 11 +- .../methods/TxPoolBesuStatistics.java | 12 +- .../methods/TxPoolBesuTransactions.java | 10 +- .../jsonrpc/methods/EeaJsonRpcMethods.java | 3 +- .../jsonrpc/methods/EthJsonRpcMethods.java | 4 +- .../jsonrpc/methods/TxPoolJsonRpcMethods.java | 6 +- .../AbstractEthGraphQLHttpServiceTest.java | 18 +- .../AbstractJsonRpcHttpServiceTest.java | 3 - .../api/jsonrpc/LatestNonceProviderTest.java | 10 +- .../methods/EthGetTransactionByHashTest.java | 20 +- .../methods/EthGetTransactionCountTest.java | 20 +- .../TxPoolBesuPendingTransactionsTest.java | 14 +- .../methods/TxPoolBesuStatisticsTest.java | 10 +- .../methods/TxPoolBesuTransactionsTest.java | 9 +- .../blockcreation/AbstractBlockCreator.java | 10 +- .../blockcreation/AbstractMinerExecutor.java | 8 +- .../BlockTransactionSelector.java | 14 +- .../blockcreation/PoWBlockCreator.java | 6 +- .../blockcreation/PoWMinerExecutor.java | 8 +- .../AbstractBlockCreatorTest.java | 35 +- .../AbstractBlockTransactionSelectorTest.java | 394 +++++++++--------- ...FeeMarketBlockTransactionSelectorTest.java | 78 ++-- ...FeeMarketBlockTransactionSelectorTest.java | 160 ++++--- .../blockcreation/PoWBlockCreatorTest.java | 76 ++-- .../blockcreation/PoWMinerExecutorTest.java | 55 ++- .../gas-price-genesis.json | 21 + .../london-genesis.json | 23 + .../bonsai/AbstractIsolationTests.java | 33 +- .../eth/transactions/TransactionPool.java | 68 ++- .../TransactionPoolEvictionService.java | 2 +- .../ethtaskutils/AbstractMessageTaskTest.java | 21 + ...GetPooledTransactionsFromPeerTaskTest.java | 16 +- .../ethereum/eth/transactions/TestNode.java | 2 +- .../TransactionPoolFactoryTest.java | 18 +- .../besu/ethstats/EthStatsService.java | 2 +- .../ethereum/retesteth/RetestethContext.java | 5 - .../ethereum/retesteth/RetestethService.java | 2 +- .../retesteth/methods/TestMineBlocks.java | 2 +- 63 files changed, 973 insertions(+), 701 deletions(-) create mode 100644 ethereum/blockcreation/src/test/resources/block-transaction-selector/gas-price-genesis.json create mode 100644 ethereum/blockcreation/src/test/resources/block-transaction-selector/london-genesis.json 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/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/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/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/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/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/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..47d6970007a 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(), 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/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/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/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/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/internal/methods/EthGetTransactionByHash.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHash.java index 49346f187b4..3a58d15bec0 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 @@ -24,19 +24,19 @@ 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 @@ -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/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/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..55d2a8fb9c9 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,10 +138,10 @@ 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 EthGetTransactionCount(blockchainQueries, transactionPool), new EthGetTransactionReceipt(blockchainQueries), new EthUninstallFilter(filterManager), new EthGetFilterChanges(filterManager), 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/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..e752dcb8242 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,8 @@ */ package org.hyperledger.besu.ethereum.api.graphql; +import static org.mockito.Mockito.when; + import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration; @@ -27,7 +29,6 @@ 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; @@ -83,23 +84,20 @@ public static void setupConstants() { 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( 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..8d8e1fc47ae 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; @@ -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 = 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..57d5e8f13da 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,7 +19,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 java.util.OptionalLong; @@ -37,17 +37,17 @@ public class LatestNonceProviderTest { @Mock private BlockchainQueries blockchainQueries; private LatestNonceProvider nonceProvider; - @Mock private PendingTransactions pendingTransactions; + @Mock private TransactionPool transactionPool; @Before 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/internal/methods/EthGetTransactionByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java index ecdb8fb67d0..b8ac917718a 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 @@ -33,7 +33,7 @@ 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.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.plugin.data.Transaction; import java.util.Optional; @@ -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 public void setUp() { - method = new EthGetTransactionByHash(blockchainQueries, pendingTransactions); + method = new EthGetTransactionByHash(blockchainQueries, transactionPool); } @Test @@ -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/TxPoolBesuPendingTransactionsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/TxPoolBesuPendingTransactionsTest.java index 09b4752fae3..87070c729ce 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; @@ -44,7 +44,7 @@ @RunWith(MockitoJUnitRunner.class) 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"; @@ -52,9 +52,9 @@ public class TxPoolBesuPendingTransactionsTest { @Before 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 +72,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 +253,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..6483b660649 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,7 +23,7 @@ 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; @@ -35,14 +35,14 @@ @RunWith(MockitoJUnitRunner.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 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..6d8a5e7ff06 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,7 +25,7 @@ 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; @@ -39,7 +39,7 @@ @RunWith(MockitoJUnitRunner.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"; @@ -48,7 +48,7 @@ public class TxPoolBesuTransactionsTest { @Before 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/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..cb3e1860b92 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 @@ -33,7 +33,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; @@ -79,7 +79,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 +95,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 +106,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; @@ -317,7 +317,7 @@ private TransactionSelectionResults selectTransactions( transactionProcessor, protocolContext.getBlockchain(), disposableWorldState, - pendingTransactions, + transactionPool, processableBlockHeader, transactionReceiptFactory, minTransactionGasPrice, 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 AbstractMinerExecutor { final var res = evaluateTransaction(pendingTransaction); transactionSelectionResults.addSelectionResult(res); @@ -414,7 +414,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 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..1bc9ff4b64e 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; @@ -41,11 +42,17 @@ 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.TransactionReceipt; 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; @@ -282,19 +289,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 +331,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 +343,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..29d03d0f4b3 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 @@ -18,7 +18,6 @@ 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; @@ -28,28 +27,33 @@ import org.hyperledger.besu.datatypes.Hash; 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; @@ -60,12 +64,12 @@ 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; @@ -75,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; @@ -82,23 +87,65 @@ 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 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 +176,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); @@ -152,13 +199,13 @@ public void emptyPendingTransactionsResultsInEmptyVettingResult() { @Test public void failedTransactionsAreIncludedInTheBlock() { - final Transaction transaction = createTransaction(1); - pendingTransactions.addRemoteTransaction(transaction, Optional.empty()); + 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); @@ -177,25 +224,25 @@ public void failedTransactionsAreIncludedInTheBlock() { assertThat(results.getTransactions().size()).isEqualTo(1); Assertions.assertThat(results.getTransactions()).contains(transaction); assertThat(results.getReceipts().size()).isEqualTo(1); - assertThat(results.getCumulativeGasUsed()).isEqualTo(95L); + assertThat(results.getCumulativeGasUsed()).isEqualTo(99995L); } @Test public void invalidTransactionsTransactionProcessingAreSkippedButBlockStillFills() { 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); @@ -214,21 +261,20 @@ public void invalidTransactionsTransactionProcessingAreSkippedButBlockStillFills assertThat(results.getTransactions().size()).isEqualTo(4); assertThat(results.getTransactions().contains(transactionsToInject.get(1))).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); @@ -248,81 +294,40 @@ public void subsetOfPendingTransactionsIncludedWhenBlockGasLimitHit() { assertThat(results.getTransactions().containsAll(transactionsToInject.subList(0, 3))).isTrue(); 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); + Assertions.assertThat(results.getReceipts().get(0).getCumulativeGasUsed()).isEqualTo(100_000); + Assertions.assertThat(results.getReceipts().get(1).getCumulativeGasUsed()).isEqualTo(200_000); + Assertions.assertThat(results.getReceipts().get(2).getCumulativeGasUsed()).isEqualTo(300_000); } @Test public void useSingleGasSpaceForAllTransactions() { - final ProcessableBlockHeader blockHeader = createBlock(300); + final ProcessableBlockHeader blockHeader = createBlock(300_000); 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( + createBlockSelector( transactionProcessor, - blockchain, - worldState, - pendingTransactions1559, blockHeader, - this::createReceipt, - Wei.of(6), - 0.8, - this::isCancelled, + Wei.ZERO, miningBeneficiary, Wei.ZERO, - FeeMarket.london(0L), - new LondonGasCalculator(), - GasLimitCalculator.constant(), - Optional.empty()); + MIN_OCCUPANCY_80_PERCENT); // 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); + final Transaction fillingLegacyTx = createTransaction(0, Wei.of(10), 300_000); 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); + final Transaction extraEIP1559Tx = createEIP1559Transaction(0, Wei.of(10), Wei.of(10), 50_000); ensureTransactionIsValid(extraEIP1559Tx); - pendingTransactions1559.addRemoteTransaction(fillingLegacyTx, Optional.empty()); - pendingTransactions1559.addRemoteTransaction(extraEIP1559Tx, Optional.empty()); + transactionPool.addRemoteTransactions(List.of(fillingLegacyTx, extraEIP1559Tx)); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); @@ -343,40 +348,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)); + Assertions.assertThat(results.getTransactions().get(0)).isEqualTo(txs[0]); + Assertions.assertThat(results.getTransactions().get(1)).isEqualTo(txs[2]); } @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,35 +385,22 @@ 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(); @@ -458,18 +442,17 @@ 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(); @@ -508,17 +491,16 @@ 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(); @@ -530,7 +512,7 @@ public void transactionSelectionStopsWhenRemainingGasIsNotEnoughForAnyMoreTransa @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 +524,45 @@ 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(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(validTransaction.getHash())) + Assertions.assertThat(transactionPool.getTransactionByHash(validTransaction.getHash())) .isPresent(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(invalidTransaction.getHash())) + Assertions.assertThat(transactionPool.getTransactionByHash(invalidTransaction.getHash())) .isNotPresent(); } @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 +575,26 @@ 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.getTransactions()).contains(selected); + assertThat(transactionSelectionResults.getTransactions()).doesNotContain(notSelectedTransient); + assertThat(transactionSelectionResults.getTransactions()).doesNotContain(notSelectedInvalid); } @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,7 +610,7 @@ public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - Assertions.assertThat(pendingTransactions.getTransactionByHash(futureTransaction.getHash())) + Assertions.assertThat(transactionPool.getTransactionByHash(futureTransaction.getHash())) .isPresent(); assertThat(results.getTransactions().size()).isEqualTo(0); } @@ -671,7 +627,7 @@ protected BlockTransactionSelector createBlockSelector( transactionProcessor, blockchain, worldState, - pendingTransactions, + transactionPool, blockHeader, this::createReceipt, minGasPrice, @@ -700,7 +656,7 @@ protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( transactionProcessor, blockchain, worldState, - pendingTransactions, + transactionPool, blockHeader, this::createReceipt, minGasPrice, @@ -716,24 +672,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/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..6179e355a79 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 @@ -16,65 +16,86 @@ import static org.assertj.core.api.Assertions.assertThat; 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.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; 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 +107,22 @@ 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(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,10 +134,10 @@ 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); @@ -123,12 +145,12 @@ public void eip1559TransactionCurrentGasPriceGreaterThanMinimumIsSelected() { selector.buildTransactionListForBlock(); assertThat(results.getTransactions().size()).isEqualTo(1); - assertThat(pendingTransactions.size()).isEqualTo(1); + assertThat(transactionPool.count()).isEqualTo(1); } @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,11 +162,12 @@ 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); @@ -152,35 +175,19 @@ public void eip1559LocalTransactionCurrentGasPriceLessThanMinimumIsSelected() { selector.buildTransactionListForBlock(); assertThat(results.getTransactions().size()).isEqualTo(1); - assertThat(pendingTransactions.size()).isEqualTo(1); + assertThat(transactionPool.count()).isEqualTo(1); } @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); @@ -203,21 +210,4 @@ public void transactionFromSameSenderWithMixedTypes() { assertThat(results.getTransactions()) .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); - } } 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..01e09a74e08 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; @@ -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/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/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..1cd869895e2 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; @@ -84,6 +92,7 @@ public abstract class AbstractIsolationTests { protected BonsaiWorldStateProvider archive; protected BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; protected ProtocolContext protocolContext; + protected EthContext ethContext; final Function asKeyPair = key -> SignatureAlgorithmFactory.getInstance() @@ -125,6 +134,7 @@ 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(); @@ -144,6 +154,19 @@ 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 @@ -194,7 +217,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 +228,7 @@ private TestBlockCreator( miningBeneficiaryCalculator, targetGasLimitSupplier, extraDataCalculator, - pendingTransactions, + transactionPool, protocolContext, protocolSchedule, minTransactionGasPrice, @@ -218,13 +241,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 +283,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/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 0d2f58220f9..f1c28413544 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,6 +19,7 @@ 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.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -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( @@ -359,10 +367,6 @@ private TransactionValidator getTransactionValidator() { .getTransactionValidator(); } - public PendingTransactions getPendingTransactions() { - return pendingTransactions; - } - private ValidationResultAndAccount validateLocalTransaction(final Transaction transaction) { return validateTransaction(transaction, true); } @@ -491,6 +495,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/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index ab4a87bc738..fcc66b56916 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,6 +57,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -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; @@ -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/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/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 111fa072297..cd0d515e5d3 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 @@ -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/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index 865a9a9c2fb..8435b8b3ca4 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; @@ -78,11 +77,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; @@ -99,13 +95,7 @@ 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 +269,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 +280,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/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/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/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(), From 9f42a3f26110913f73ddea7f3d20a76fd3c019c5 Mon Sep 17 00:00:00 2001 From: matkt Date: Thu, 13 Jul 2023 15:45:33 +0200 Subject: [PATCH 09/51] remove v0 version of the database (#5698) Signed-off-by: Karim TAAM --- CHANGELOG.md | 2 + .../backup/BackupRoundTripAcceptanceTest.java | 10 - .../DatabaseMigrationAcceptanceTest.java | 10 - .../database/version0/besu-db-archive.tar.gz | Bin 102404 -> 0 bytes .../operations/OperationBenchmarkHelper.java | 15 +- .../RocksDBKeyValuePrivacyStorageFactory.java | 4 +- .../RocksDBKeyValueStorageFactory.java | 19 +- .../configuration/DatabaseMetadata.java | 2 +- .../unsegmented/RocksDBKeyValueStorage.java | 223 ------------------ .../unsegmented/RocksDBTransaction.java | 112 --------- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 7 +- .../RocksDBKeyValueStorageFactoryTest.java | 8 +- ...nDBRocksDBColumnarKeyValueStorageTest.java | 18 ++ .../RocksDBColumnarKeyValueStorageTest.java | 100 ++++++++ .../segmented/RocksDBKeyValueStorageTest.java | 136 ----------- ...nDBRocksDBColumnarKeyValueStorageTest.java | 19 ++ 16 files changed, 164 insertions(+), 521 deletions(-) delete mode 100644 acceptance-tests/tests/src/test/resources/org/hyperledger/besu/tests/acceptance/database/version0/besu-db-archive.tar.gz delete mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBKeyValueStorage.java delete mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java delete mode 100644 plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBKeyValueStorageTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a47fb3cd942..42e42706754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Breaking Changes +- Removed support for version 0 of the database as it is no longer used by any active node. + ### Additions and Improvements - 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) 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/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 894c8e76a69bbbea528027e44a8320014b086e66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102404 zcmV(!K;^$5iwFRNFjigw1MFD|IFxJOH;52fvP8XRWX;ZuU6$-?_9!%lkR^^FPk~NZp2o=e4Y(*-m_-3Zwb9&$Jyzlc~-}jup@48O^>$jl_DA4L!cY7E z0Qt@SUn{YQ>qSS<*Z8;fUqV6x{@?5`A^r3G=f_BRl(4J;83gj}mI6O$Auv*vH2Pys zRL5p^^}TQEPWB$+!!>CZ+tg0183~D(C=*7FO~4%aD_oS2$&-mL4dNwLIrtlwZ=} zaaD73Ph@r3cE&<&OgCb}9*cdXKsPn;lwF}Pf2DJIsH3*>gpz`ymh-tLjcql&y#NEC z>lY13%!gwNDWM@X(>-Jz^CS%>{SkcfK|2%V*3pF?5Gds4?Yi9B=IndM2u5KQ-Y>7R zZSHjB^j4<7?>!!Pc(3!qwo{(coD|LN4w1u#NnvHr@9vLR*ph6}j(?I&d+G)0`Mo*t zz=(vMmp@gMd`3g)HJ59~WqS`EFINY9gV@R>V>602vVH=X6Lt?Z96rxx&wgeqCPyZQ zK-n2S|Csiy+XyA+%dxCtLMe%dCbwH@xbT z&m|9Fs2mdx$)!*%*7f!zy7K;9NLy}ArR}?&BbJff-JkrQp*2nqZ*LqmOynz28Uv3b z==97o*TZ!62uL)O9Nkom$+RuMm}C3gEg1#aoF_Vrh=yChwCG``*2sI8LG{QlGGhFJ zMbT}oHy&RswzKqY(*_TXJbfJF=Kz*En{G~#9cyVGoM8&KbXj}pvtjCjPek1W!F?pN z5DXkT=5qWcM|k8>aobL{mBG?NrP{$|hORXocfbP^F43miv$?2j8GJ3=@lf`$r~bd@ z?)GG0x9SMT;05rOCDt!3BW`#Qa^bK-v*~6?ve0`cPrv zfja{4EO_3wS$$@{nQDyMNdvv?oWTIkIACM&8j4B--bth8P?>{6~pTc~! zWGe!$-Y2^1#}b#)d{NDl2L5Gl;(`;Gmnnp})Z*?2Buz&RqqTPW=B+LQQ4f8dVxvRe;S%es-$`uvq)5=nG z@ILhREyaC0D_V1ouF2Lah!`LniHo6WMlr$FskYgJ<{xr!43D*VJ11RKsSS18VBk@} zTR1s4467uO9gnWLP)8-W!8NZap%_uaCy?q>q05#{bdKE60%_{nx%Dt=4Xco{hQ7uH zql{^7H!~0H1S!oVcwj`Q$|M`5aOi@O2eRlwc0t-Cn-B96c01aTbMm(9x8r`d2Yx*u z8nHmCVZPa8)6{+S#h{cWnRmhlwl~UAB~;T5?%(ttHBwlXWF>4wj8-{?thYM5H-r*a z`}T3aMpgEGW|GmjPGt<=Iy5$VsRKL?CfKeUCMhO*H!4W>y1UWy zQr#8)i$pZA6~kbt$m*cmCA%<1BM}s>{yvN7=qOJopDV+6*0{h!lO{g1#hp)K)fv7h zCUDhwlq2h2HvG&@YwN2oUncmP#S+m(coyoRbi>vLNgh&FE+6+Oi^Mdv+amWU7gN`j z-1NXhD38*VeegaDe(=DMyKS8+Nf^8`r^J;}Z4=nRsFx$eHRz|@eS6a{Y&gp6?->mX zL?H$Xq}Okm5dx)kx{lMX?ZPGIE+Lf+v^y3`RY&3Xk5u)uGQWmUv~v+CkSV;6L$k6) zd&#T{slF;XOTFTiTznv|h2ek*DpKV>cof`lJPx}>`Qln^JO4_;&Dx?HOGy=NVe2$& zdd_m?Z8rspVBYyqA?r`acjvXzcpO4T8!#LkPdMc3!`wO%;brLq9vDUcRYNw&j9y%1 zlemJnR<@$&_Q?1~U{ZXGY^6fI#A$*(ut4F`8jJf!Mh&y_aTeHXMw;9;?om&+2*k`7hEZ*db2qAI+ z0mUE%m>K1lk4o9eaql@V$DHRFX|8hIS}It4(rlsOt6W2D!NTj=x*JW|tewgFH-Zck zJ84RHUtqkd*;+c+J0VISmOD|4p)>00=U-bipB0Y0ezBqJF*Wl2G9xVNvP0oMxl;r% z2!+#JQLCwxr=pr?OkAuQE7S@NUV28wHVV$&@$c*b4@}vD$v(>V&ZP|$6OBb7+Cq1% zD`7`-A&OE5F6u%NpHEC3yD?1p3uyDevPc0#?4%oc(pg_sE)Q0iRX z$GJSP8EHFU63iSGR6_NlB(J-l{dLYO_j0;DqAMSZX`?niYn6+n@8Q;wJ|)w|vr8|$ z$<2>MR`Xx)VF8b$d(A$xkqL^2I&Ei}-OV*@VlQbow@|ymT(HK?LXoKmBAV$@M0*Gu zbib{u#@MC)1?T=?VY$&qB~udAGz#&*90d;z{HA3OPtMbNOUKrcou2a%WBOa^2C%7h z2mZ;6FDH6BiD=w1yeqnTB~pwZqLjJB;x0`QD9#KDTjhrR>bOM_ ze?GR#W8k4-u1-z-$lIo@(j$`U`%cQUA~;rAq|K+8EKt}n%Gt|+5LyywB~~R|`VM98 z7~Oq6?YOvd9_9(Y`Mn5|`^vu#_JIdRreuu0AbW?cdlkoe10E<;AE!EO)6VeF>L|yM z2YT=WanmzC)qpu^gi$;B0#X>UpnjOKDQb|nmYKZ8uVwX`9e7}_i3G8v<_o9m995Bs zAa#FHrDG5A^*zrrR2_>VS!mxOwg^}t{(j2?K)QV^N%M1?DF{a9w+#Jc6;w!E^B46> zvb`)l-+Jogu)vz<+{8_2rSRrt4#c;$_Sf{*9nHP=g`0PVl1!C3^~*#arOJRuK~B(9 z>5#|WVH}dXr$)|NrP7J9>LNG|7Nrv@YJ?MLGl=%sC^TzuGo}yZJ;u5I=^(;^A~aoX zD9z)k&l?7Y>LKvJ3_8+s!;~$hJZmiqZxXaS;WqVRjK^k#y z-6|5^3hPI)y1S2vd8z&!3^t%;Sac@&5w?x>sW_V|D#a?sfY$nC0j*;dc&?X;;<(Q? zSTqMY(6wf!*!;#!yXy2v?`{U8&IZSWcS?)I&j7nyQnE0s6~yceO&`+x9n7q$;YmiJ4k&rUZ%?mZDhqmYIfd(|MmM<#PWa4uEJRP6ASo zke4ppK%~E|N>?^*xz9K; zN$#-UQ9L)VNJ(qO$==rs<5a16X2r&&;u@uS%O~9eJTUE}#iWO+s*yhL$3MW$i`oQs zdrB<*pNDPrPbA?=%gu?K?D!XP2F264Q1z=53G!zSng_YaUPqJ{CizKU!GNwDCx^wbpWyFxvd*XeU(DZDugG+#o|G7Fd1X1A+=TV zu=}%s*=rQUuK@BcxZ43wq9jA-U*d{}6Fv#c2WIxNg?dO*nX6(1Y`_C!-Sax1(L4A< zO7~>`@;&mpT&<3S@F3UF+jGUqj18L~31AfEhCZbUg)L487b14@}-x(ov0#8pry%`3EnA_Lo?a zYwl|Lq!`u~GCP^BJT3U{s|*l{UuOYnN3_SWaz4#TBZx77-EBtU#%Q-VGj*Q#HT25t ze9;-9yjQe|2NAPNLPa!acw21pUAcJj6Mjs}1F6@V3uM%N6`b8bJa*4+b#+eddpGNu zb^g|A#U<{8w4FXANw4Tp2bC1$c+=O2M>PIRtLy$YM;)NF=y3m&Lb&X)v)ap6ANSea zfJd=_c!1aO>c3dG?szKOHy$#MJrdaoNt8VjQOMr&kdB$2=jUhwL4pV@F12 zMwwZak<3s=`swL?-{1TG_5Aakzwgiae6R0y-QVkeuKRmGx_`^{ekgSsxlTTqsYq@ zk6al(H9xQjswbme9DBG&whOf*T~K+=Mg8~3`e79@0c}#<^!{E_tnhJwDeTbnnKiP~ zjNjZ?=e1KuVv&c3BQ?&R0LP-133FNU$?=>DfI2b(P;K)!H&9Isfa)tJ{{bawC;)1c zp#Z3~qX4KBon*0(tFg{l4J|YwSyo~==qvM^6LY~ z48*#}ThRK#mqcZnVzqk%Z>XpYzwPq0uc!zM5KnM@XY)&c zBG{UaX}k-nTx${IGcsX2y+{S zWYF@5`(l|cPDxMR78CQXS#7>59mDqpRY1F8h$iGWnCluNM1(_#7%LVEwg}eoLaatLeuz8`PR~FlN*P)BuS1nE}r}WeO7db zKi&;0lKf7Hn2Er3?Qj9l{Mc4V*@8$p-3R1KDL zHNqi*XZoRgPhxHCl;r8;6>Q|;2IHEy`0~N)wpkzeILh87GxD}B)rhs^<`fwqI(xB4 z;OTSK^_EDBk@iG%vVZe11MeY5_qu`!&Dv>LEXkI?$ zJ6l+V-s3~q@>zYqq{y9hE`>~q&35e6!@V0LpQ%7J-3^KCzC{dN2HP3BskZcc;!U1&7EqKTWOo< zi!|0-ePfQH(E$fO^Pi&@w=^17MQX=|gh(}Ns(U^05_bE95lWq$>LKufsq*Z>me^&k z%jr9zi&f7(6|GSul%I_hQ}H_gw)`lE3p{rphj!jI4``TUvOg7zi@h>>T*9>$K+yv2M1hzq_{o@|oadO<)tPaio{AneS#-TU(!O+sx7AUF7XIYUwaGL{S@EHi-27 zX$qoAAGRrQs?)`p^=0MEl(p@KZ z{*8h#l576%;qw{J{B8%DG$0zl?*7v8${TT76V1heH9 z?31lX^KaRf%1neJlP{4>_iQ7CId&pD%HRW2eH_a9 zNcXh;W;NpIj91Ucd<(326YbblHeF4jZwXnTS%(eD(rFqs-|hQ(?X_lFX_jZm=u1LF z%6c303-6@@e)zyxah5D&T|HZVNsLY)f*!?V_!bVf(hJY<&YF+Kw*ON5_s|~&K=BAJ zf{O1%QxbF>(gs;sZf=egmbSF`8HdE-SYzaJp6YAm2p2!uHvY@%066c>6dB0MvIJ3V`~u0H8hs z0H^~W3V=F%p#Z1@5dd{Y0igO30M!}*D76Nl1QdX(l;3%~jo1HXkX}%-@R|%zNmIrts=Db(@koXB=|NI z+9(N6B|mq3n$18OL5J(`?yK!)>SY7o(RIR)pM;6yK=+%;OPU9m3o&0*v06FnR!F7P zS41Jq$Y$m^MOz!Ib{PHD@(7GmV9omaE1MFD(ezkfxxg6$r51+_&H5C8mT=&o-3>r- z_>TlY#dngAi8TAd5%zPEE|G%|CgS7;3oNwuso(LN*s}5}21!LlgI!UC5feSXVlplE zefYhufT_^0K>7MNbWam+{_N)N9)|JV*DDVDUBf5g3WoX?>(Wlegg8XfeLLK?IhXA> zzjCCACW8~Htpm=)^KW@_F%K$7kOKlSIjY1$`Kk>24tsvv^0n|;@lMg!mDry~2bsBq zwvpJs>kduK6BO6Gn@Z4Ied^r6N30d1G+mZ0lxSR;J1 zS65SEya(ajP3jMol^03O>pW!9&p4W{!wqE`u@h{RHQw)do(s--q3HX6bAXENug^xe zHKsI#*EgGH8IwhS84qO7wM(K(JgyR`>9JGe8HWa7btGCoF20UFs9X4z-YIv%BI)3s zCl|GcQ9Xf;n;PTAc=$Nb_f^SP1Qf~FE9PW-Z-{yg@Esm;B_&MWA{MK$Q)F@g(Nre+ z9!pgIEbA#uQL7M?O|n$Ey^|0uY-M;ZSgN@-5I!{6Qxn}?o8KM{nYq#4(9^h_q8QJU zN3-xjl7^w_HA033MDy)OpW*}5ZGBhj)=jF`dkXfw53T$MBStUkj~%x3s=$W^4?|ES zosd17t@$iu)hD8)$*hJYU+P!$IrPgrbtGm=AR0Qnjsau>O&U?2^y^1FWF!c-_SaKdD;Ls{)nU?mBrP<{ef@q#DhU*3@ zr)6@}mruQlb~7FB*W~4=Rwjx1VNu1&ngAa+4*e7x5re+%!7;3}o12cT6hFn5+}Qm> zjbxJWx$c;N&zkrzc}lx@e7lf(^XgEHLnY?(#i*`k*&b!21F_>I1B}C}uxA(Rx-2Bl{N&;c)6n|GQ2*#(aO6j+R(_Xse1m3Esh!JHU%UwB&$>8K>I9061 zL`Y}zkEa%ZO6bWFD4I`}Kn4Ft0to|il<%8;uw}g~!f_7O-ja1NSIe))wo!H=3nxG= zg$*oagdSN@k6yi)seT9Ni}Z^@YHVlqxIZm@Lqr6huZn>2E_h#jaZ-V%#y$QH>vrVw z4c#%R?Cu{kNya54!XvG>7Cb;F8US^a0HC@)0M%{)sLpT_ErePFPyz}-X&L|}Gbfxw z71i%MJ%|kdt^$No5GMiq7zrQaKDR=Exy13R*5I*Dj-I@`^YRUvmIZM5UdKuxd2Hn> zwCh|Kv<}qv>P#z`VVn*>;uEv!deY zX0q-1#p?WFLeGQ{?`58>n`4MrWDaN#RlA+*kTGJ6n}ylPzyugfrn)EWEj4poac#UK zjS7cRLM$XGJeOTLRLRbM#8SH3|ORzbyo zQatIi^S;vN-UL$jes1;lk>jB3y&&*|a>3Z41FWspcmb0~4-e5Ca zV2+7e-y_Q}Hyk1xWWBjG0ra95UKIHi>)X*@hVf2IkYr=S{k)By?v|6dcVW!=hZHtM zB(5mNwfa*Z-*@HV|7W5B(hbEW02SZwd)CA-fte4)sdMpllLPya+JvhqIx%1E@Fwe% zwb)F1$w9Z3p1yh*y)OD@jqv0(Z42+0Y};1rezuq1l91R548myO@Hj0H=-1rBTG|-v zA$wb+(R#P=+H&U)+ct!Y&Ry4nPVn;TP=8)Z{`jo?gW#ALF=Mi?#S8D{>YSp|iQSp! z*B-(6=33RNoz`PvV6}33`#kamvlka-f173qN%H|Fpf?2loxM))ROOdi_1*z7a|xJ%^z#fvi5^57S&Z(9+Zd1#%6fUD6@|J#E2YW zq=%c$`HFMt?hEk1cXmyWoAtMGnv8DpItshoPA3p6)GkN&sDp@wB!*Lb$R6~SipCFO zC|}gM@$sg0wM``NSx5T^dSnmBkk{*c4?SjqFChzfRrz`WsPMwEs0mf#`K#sE3xfGt zNRzPg5?j@KgyEno0%wQz>yHct+H?^+Wz5QFYy0lF=$)238MMXS&RN7TS~OT^Q)sW9 z8^34bqb(5I{QZ?#gVDS{LlB;`ego1I$M63W3MdZ$tbz*ePj#fy?7U_T#?hmyk_l0F zRLqOzcT^}jAZ-v{n(_466DJ3&WAsA3(X6vaRlpsCYvU46I!mHFWH+$ciwgO!a{R1o zF!tU?D|y^;{vi4O$2IqO4I7CsuBC)sGos>K^fT>a>;x_85?mZNn_p5@@iFTT%_P(qpaeChCmO#z~sxk}OPl{794$rC?{V7^x#%Vwy zi}lUfW#xpV*fJogEa%U z!k&`v8)FR92X*gWda0z>5YD|RYP_H;kuf?z#*l~yIma{O~aTe=@bg0abCt3FP&_%5EGH4$c#PnRINT?x%rB>!Y4$_ z)M6MGJ|zn}GHvbM4yZ9n$FOv%Py7;_D$>0Dc95C8GEs(M#V-UzBNR+3^>AkZQD!z-+4Jehv2#d@tc=^t3Y8sM*%{g5*o3l2GXGDv{=esWUfpl*_vgju z`dpvyHNM~LzD~%Ar}D>Ue|ppP0iXCy(yv<}nrAdi4R4kV>OGKajmWtpb)v_cDwd?{ z z3*)K3PJhMukS=|-QbKXQBYg1NGn|M)_|RymRbY3LugH<1kRcs30_PniNcQo?%{q?q z1F#w^%=~As8Bo z-_b{w?#+G&;(=(GejO&r~erxEep71&Y}7++4woo-K$nm!f(bSk(~WkDx<<415cshyJv$@KepWWf&D zid`e#J6Bn%Q(Z}(<0jXVY(|{kQr%ZqNcoxY)uqNP7@ynUBx2;6P1|*+zF*sJ(+Q{- zd*PmqiF33I*lCgAtO)|&RwgUkL??903`qdnN;Z$d+2$X{Z-^vZgjPzDKQqEOtwBbf zws~nsHKn$oc68PI?)_8xkS$)Sdr5{BQR9>0Mj^j*6BL1GnF-3W{|#N~WU@GxV27Aa z?;1WrN6xUXSqO6Dn?xG?lt8q$)~|vSd#p!7EpG=5NXY0P$A$N%;rlxV<-gn}t5}ez z>|Wr!17oXYHg5SI9^lz}uIxNRkMXU+rEVI7Z?@D_ymL6mIw|kmM}WXrPV9$!%s;FaM!~A#9)-#`)!l z;9&MFwS=5nf~*9O6}eG<>|wh|h(tWa`<*y$-Jf7zeeI!Upib1~-COP@g*?~C*$5(P zYAjuoF5zChejk5=2|h5-(mv7?EtzvzD{VUV>7KBg*goMj<2fKfYKTluIz-{c;_N>I z^$aDhvj_y`bu<9w3IK{8@W8~6%yiGoJBUBba_n;OI{v;aHGSh9NuE|fkC71-Zq8#c zp=ig38I6*Xq*EH!Uie-hfgxAh&ho?}q*!rdeG_5qK6AdLNJ>ZfT<8tur05#+DJ&@s z$-#+ZIQ=|CCwPXMb?4)0+&_gvlh zv!l*oQOK6&KE1160B6#OKGr6btS$WG&s>c0RKH5_E6RDy z;@O@CDE@vs1j@4i`J>p+*FE)0cGUfEOj|W<8i}bb4_+)R(A6#Xnl#_`+dzPl#2sE` z;4ZznJb0oj(h?&uR(tLvH(R?v&>CL`@iHNN-JZ%^LXU_4DLK3Iml#CIhOw{f%%2#P z0HPN!19|v8vG@1w3;;zH_#-IG{zt**(S!DOm9)?ZgE<{+z-$h;?x)*QHsz?570uF$ z_1#KvTv;m;<%TcVv1no2XPLgEI7Q!cK*&;ddeqi`zX$akJ{2hPxVgzutUcn7^L~rn zI#v=*#~qcvd7M{4l2JHT(R&KUt2Un5XvR8zD=Z;GQ1craQ>qk`ydP8FlxvTOT06#HRJ?()UW1*cY?RhwS z6rp0TFqsG-Vr!|GxkFFG3Dr5ps#|8~RISSa zx>LkD#gdLs78wN}nkxq*#=0&h11lYTsa|1ve>UVfFn^KEwQ|gIXh$yk0U#Qs50|+* zdoK`NExk5CCemE4_!blF>c637J@5lt=2ivc9|3fjV*PdM67LCwR}?p=c-Jyn;s*t$ zd3nVQafxoARKbW;Mjbb@O@0M;OB*9xvQ!;4{Fv*z4a0Y-ELnM0ms$A0P(@iOD69;v zibic>TgWMus`B_oIX~_rUZmcpG71n{{H?6lvV$^ zLLm^Zs-Jzh6T5!j6fa(oML=Llfh7A~hV|fkO0k01;!i+zOupSv*mOg+2eo8HzIVEP zQ|P+DmT_@a)iIKT$dsoTJ`NTlHg5S%ngOILm4A?z;4hwA3yVYFnc$ahI}*ju=z0mZ zAVk8HFZQyU))tG@Rjl`ze7w#zTCIh6CsFHTgzL8810&oXuGy6D z&l9^u9tuY@KhgsQ>azml>@zgYqIqRY z`qYwmSgp+RSo{zNFT&>aLe|@V^yGt2=QfCH+URM=^9H_#d$Tt^+oB|`E9OUw54$h} zwQOAQQD8F{IW1aUW1TW};owqNk zNERNo(prifDciVs%4hhK`s|{lj2A1N{qKq{dw{F^gr#1Fp$g`PW-BzPUny-Yd}2J+ zIezCRE3I>j2JoMOj{++`Ne7wWuSS#210{#E@)KJv8aGakF0p^M%1p>&^STE5ACc^CjZ~FB~UE>{SzqLe)}W-@HtRM{)Jb2LCnUz$H*gjVgi#F>*FaWUSvBy z*{isXv%iT3pbCOtn4r=$8h}cj094Edpu+1f98kIjposoOOVK)FBV*g(r1wes@Jz9< z!iSJzS7(j1ERJH@?EcHdZ?Oc6Kyeky_@ z@c)$zW!rC=?tUKkNDJ339TxkJFF?e1w~X}u2~wJSdkhjcl58AYWx^r_ahuZIqoD}fC&pA4U zeL5eIM+l-}&@q>oH41!sy?{)%CCYlrgu+sJf@9q!yO-rnLAe8bXrxd5_?cq&)`JOT z<@tthiec??jcFTd)AFQR>lH)wnL(|7;2nE`h#4M3Qg>1aG%+aRwFm3zjRe4S3Ts%!M{zA+7Cf=(RU_q+hl@qZaT%WKN!gl5(zp|t3G6`M(b)n=&rinO+&G{6~3Yn zJDV(91mo&F?--m;?08?CT^0L-AW}IC+&ii?ysHXo)h2K1Iyl2qf2#wEz<*bPQ1<<* z0qeP+Dk`R43F_4h&?2C-UG6OMOi0Y zC|CT=8xxJ*BqLIHPsAQq#(khJ=d%@6R$^ULT4#gg?VOiCM9w~a?2lMsWA2Q`B}r*- z8LknKcbPHEeO~4kl3lIxmQ52r?M#~Z=q+SUkbBthV_59Jj1oV`Flb(^d18?q*{I8K zI0&LqnamWp?B~TzS7DSt&KPWZa@e>^iB?In6Hn;QMm~ZM%|uF!$S9ZEXO-cHi7$U} z4#}bHhxT|d2?Y~+8QKy*2f>eqiMiG(4*p7#<4N5_4p1RKJ!95d!_&?UJGAzoiYZHRf1JVN0 z0wO8h4Kj2ybc3L@(j^K=hcpgIDBXyFNOy^#64EK%2r{1x=X~!u@1N(#`}}{dYwmUL zRkQZmYfV82yw6G_kIs~aYyLej0*J@UZ-B(Rv~k+32hui}6<=xPLnAchP)pE+_)gFu z;#H)s5Sc0W@4Z)RsTxqs-8WI82FqIuL7j6rJzUbvoAp`KkE3Iy*1i{j$AN_e(Ju!s z2^Zc{ZDJCX34!Yzg0IrsmFu(^tt#&M4Xj)(gLJN1VoyA7GFGz4_KJ{_hON7o-0%+2 zDs6bGjXEO+9-1(cxw-)KzMI{jRwA>U!ji=kZV>tSlIlJ#jDSP0H(V{sT*T{ZPnKVx z^pMigFf3%ayVKM>R#5b0J!AB>vTHDiE!#G!iATO{oTwMW0`;h}gO1&A30>@;uGwEK zleaUP1aBZM=fg&)KGj)`?|A1SK4Yu!m-89=AjwaC8gFwq4~IdVug;$GsCNwKMXD=I zU`uLaIX|^Jny=kuOXusLquTloyaSm#nGuOqic4_m9IL-zj2Vj;lh5)TmHqrujWJiL z*Am3%_VHn4qvm<(a|?9m9}5asyv17^?cdcq#GL&Ig#T3ifgHssWDIfRyw7iX|1js+ znJu$avLggyBpFYst~r%`dJN*23NvpZgkImw&Qk70mr!=&{64YTDW6ncn`rnnVS1=Y&-Sff>Gq-2aypkT~!RYc<`0b@yKZFxI9+^Z; zT~=1$KyeHCi$LK74&=w+KrSZ`4&(-qK!B_h4s;TKXyIiF8H}A9IBRUqz$2J7vf__x zGYUdYLM(>3V~XJSV<1PSwe6ep9cSnj>V|yxH`Y^c^TQb~$st*LXQ$iY(ln$?f4b1l+ zrDH%k;&y4ozQaJYDH#nZmwSQ8j z4Mio@sN$!v=7)I%@rZvM(Xrq>{Mp@#@xw+x7E{L+396dv=F!~a&x~v`}Zf!NsTQtnL>&!lYCW3%~dL<;@@HnS+- zgMQvn`ckl!Nthjp#&bd=LP)F$)31xI86KrzGABJoH|3@X8N2I7d^@ zMXui-U3f<(OUkfJwZky&bm|)PjP)q3xG?$(jo5p0nkZb7tUAWer3H5^XKM0e(?Ut* zeZ7VSoy_w<+$LOYKC|Djho$d@g%kc+d;LtYXbU>Zx*!&wU0GLe&TWirxUnOfXg<%7 zRtmw!J{*$i+*sDVLz{Y?pCU_-z=GNrJTPi@&v)d*GBFAj6)Epa4tUu67rL0+oO$;w z?2w)cU_V5rIvI&iTrAnFjBKrSl4_|7SOl8i1#lgZO_qM+7N@=F1DQmo*o6vB)N$iAS=KycG2nN9LFZQqGFK{irSu z_X5@IGo#y7OWaJT%*~Wu6$|WZfVjXW%*V__i-QaW&ZVUohl4p2Prgwuu#o6gS~*%b zFv9;Bd3$ZwA32Od>U~mvFfq+>KU!NDHDkDf``*VN)f-a=Y~X(Xa*;Txj(n{*j)|cTcwJT`f{JWbMNQwRe1|-B^E}~y3R=IC6OoUpa z9If16ceU^g!DC5ibFCxJ6Vle5dNmCWolIMHN~WJzhzcqRS#L3xyv0$2=xTft@lk-2 zWl#V-=1UvRb7JjFR^^;4cgPKJ%zU2Y`w?ujQ1etUi&9&iDO?S^0m|e8;Xqjx94N#2 zBMwm75eNrL1>iu@84eT{E{m)Ho(c}6H*laM{-Xs>1#Y*9Ufm?0(>JWKI~wqPUEJ95 z({dAc2pXXAqN}VF*+Zya`s8$87tRJ*>|2GU-79d}O93@TeJs5jjRjW{lbut%ASG0=x zJl}!CTD0OGcwjD6q(84J8!LO>bmf<6y;jEx#r?Ld-j4{!vaDu(+{}5^bOprUzd{9& ze1Fcv;Jpi%Zvd1mU-SHhMK+Z$`{7(3_Ic5(5mYL#r>y;4=x>a#v<@{} z9GCcHHzPPKmwUJF;v9Y${te;;1XEnhwkaBsTlPnWRVH}ka~(^)wNOiq1fFD7+zJU( zBpL&u=U#~e(T3#vQWno>e?`21$!Uy%SR#tER-!+YQv(l8N_*^6mKN>YO)B4uY=MH= z0BEBvp>Gin3F?;K6Z%Q2t4%cdW1f>gFr-JZB(E;JH0cL;icm~1wPi;dP}<; zMv?=+)DsunbHkRA*Z8e&WwyFRjnT`I-csqdG`7)}XIbOS@_bRwCGQzQ>~ILP>c_r~ z$~BdL@~NzzzESm|)BFK-#PxkjlCSyhasr1)7x$9tlg@M^{9L_Llqg%&rJ1&E`(&Q9 zZQHhO+qP}nwr$(C)#q0A-!;18DW1Prim~UKo9@_7jwU0FLF0=*)#N=J{s5;uGwv@! zrq;KH2{3$KlB)n7nY+tNP<%cK#^Uvb6diZZ3T!n8(c7J_V%#2|lnxmYz=QTp{;4ik z)t6c3?VDoNP?q~)u*^W=psRJwl|;iL#InPsl#wGwQ%&Lw32HslxuC9aQnK9diE#%@ zFkMfYZCyxnBzD;J&+eisd-ybbk&%{~*I752)r5k>O@!nh7%)`gj1!KCnh~JPRu0Gz zy%ZxG`s%uFXSoQ}p6xoRN^!MoSIskwq46C17^5E>vo4@dr=iZX*tBo;=shSdsXsSr zt$$2Pds2jc7!QFB?rUfLjyk8_*mA+w7iZJ<1jNM_Kiowkv_+T0yzm*CNvvJ+ndEf{ zs+*^taSnZKb~u+Kh|Po(3!C(Ju}4;Kjm@_pS9wgDuL4K;GvK=8r)(0id+{!@2g&e~ z%G)B?7gQ}_%4v~lZaG%8w3XDVe6W8gPi77g$0>%pEt3ysZa4c&Qa-VfFGtT4u)`e7 zKNvg+9;ci&u4Ysgq9xqIM=NqpC-sec#L?&3Kkf|%#hBWd?cZh3RSUte2M)0wFWU4z zJ`U?vGK?9Kg(WPb=nz8bkdPWDiqHliS!kq|5EnI;+0V^ZgK|AF`l*Y{Hq;GjGV(Z? ztJv!rzv;71y6BoDJ*6E{z(0%IL!Mj7W*3mh+#KEOT~X*cXyZdA^;FiifvJO zxmAEW#SKV;+~E;V6uQre=5(0C>-6*TM4Lqd*oPK-)nYnX&)FDPEW%mR*B-lueo8I) zmT@^JL%ApS{KM)&kzLBV}r%5E{>V#YXfalR6z!T1M zd){Ml8`n%?DRR9nb;$UJYg_$}vKTnXvK6hrenbM&58~+bBE6nMXhfW6GxMH#OtGHM zsrvdI;QY#PL^WdqK7-{=L0W z_O~A$C-8rx3|Ld64wR#PA~XQOC%*Ri#5r&%Y(s#H8|?C~kl>Q;KnMI4VAqPIXhVDLy#u7~ z)gCfW19i8P^bJclIZQMBl8eGD9G@GQ6h?e&n9l)ZpBLT3luXDrLGMz9Q4>|fO$;%1 zt@t_=8d>hz&Q~wGP2zpxyWSA-K1)qqglQOK*BduxqG$d}{p|>jOtYI6Y$4^Nc3p6H z4Dp413ai&t{&S-h!`Bq=ie@Hoz(L`DEg342v&zBf>TUK%#}K~u&&12%aV(a#Am#o?-frZ zRPTPVF35rj8$#@Fgn}Kx`>$M3E~~>R#GtWZ>@eA^lDx&G(`4wF1Q|~xk#lt1xG6$A zaQbJ;s3>pvxX`&r(hi1d)II%-I8PMnZ);0zAVszm-<1+O>CZzudt@^ola;)}^GPhm zR%BG>j`I-sW)NH;c%jzmSRPh1VQAx5JGsY%TP#uQZKfi5iM2C7LIz&CE;>ABSR$>S ziN3)pzxhKBwfpF^MG}`d&R_tGxFD`E3uNS_KOXw;S1%ZN!Tl^b-+*?xRcNV4oV*Y2 zE4kq+LyQbLxgi^TrHou2_NC-i)HWaZLZvp0LVx%JsRvu#(L986@Sd0Shh?@;NmVlm zNtDbgf#RNh+y+U-LEC=%_gnxC`=j>5X=r&_7WAgi;1$BWxGhvv%xvL5WM3seyQo+YsZbDX*#cn?DZp`o}HN?TB)FD1~^31D9z!59f zJ$#7O>_Nqa^^(UFlGLX>o6s9RfoDuHL8fLXX2h(`eR2%PrM41M4Fr;S=*eBpn`L~R zzgsOaCr3JPbE$5B3&Jjk*Jzi~>;+d1g_8j^^r@XQmMNrg!20G3L~++;zkIpep;UTn zX~5^!ArEbhCphZyhIEACU7yjB!9{Z>v|3^@kHcOcLg=LreTHWJ3>=~W0=yLSl&CHT zM_yr96D2{&uc0^Jfi4!B=#{$zqvr7w#_Eg43QoJ$xPs+0@K_`5t-o2TGWP}CTntvYQ&IyYYD>KMejj;FDyG7ILqdU~%%)+6WX z*T222uU{{o+2)(eo{`rMo6!magcR$9FTlf)P2bdN=s=IJ@S{(~OIz^q`&N14md4ha zoKRUItLRYjR_xIODPezE*O1a>;>H4dcF0+=bO()csQkyil01+QIsH;Q3*Ulv|MSB@ zaUjuSLJp#ROp;U0pOHHq>9;U-#4g|5CN^%8nye-Ou zZy#Q^`%mHcYUvDbQtL-=n{IhZ@3(&tBo+WrUh`DR@-{BGV?T>Eps{;e;&ptBS26Pt za+Qs>jwQ6s`Mt0JzVl$Zg%oTL(ga46j~bw&F(&4m4hC|$iLXAquGjUOS{%2xgJC>;PE4~no5V~dNA%LTJXsw*>QJHote!Jb@Qlw+t@Nry@5@x|3KKR;mzh4T9HfU*+Yt^4^5 ztBg0#4DwvhmqB}kZjm7PQE!?%lWkVQPYhqBMN9g)o09dobM?Nz&-mk+^~lStIAEF! zJk0Ac{{3@#7Cu8^V(?FA11LUy^d*k7;2d*2RVNwqb}oqvjTLID-jKzGJ5OYoV5-RkNry__QL_z1nuIP0DU@FVEtH?ZN3U~Ft#3_`+}&QCVyTv--Uyhgy~*6+v}4(< zmv4r;c}(RhNJ*Sb`QJ)kG@axeEp_AagkOHOOuT+;(gRl-v?pg@`OH-J+ev$+!aE5L!>V2wmDm0hvs?bI)o5)CnXW{ zxgM7e?|iKmaW;u0m_KFbt1Dc(}36*4cmmFHQXpL=BNH>chyGP6<(?Ul5ZP3b>rE1UhibEr1%ed7S$Q?s& zr3^9ARod7tyQKV9rzmSgao0mD5!$WuG7|-bh76jHqcx9onKSnq&EBo!WH%(i_K|S! z|CGVd>*`m>>Mo7AF1&hw$l1QU0aBw*e_E7RlUD>3E1z8hky-R*%DrkvX^ z-OO6@0yEa4(*23M_rEU&qTUC4W`GS5Y}cB#3aFe+IGUXZva6GX;l@8Z8U!zLn^9rM&J9>b&4`R2*!n z1?nmiWEh!(RgcctVcCgl2JB>lmLV4F_iqn@h;0mWlb)iE!cswXZ9=D`hh?&a{w89I#J0q$7UKNE60h6> z%c^$T7NB2+3awoMH>SKS*QT0S7fO;&Z2Ewac{InZi$dJMrp)Uqe7)OkM?v}X0TR*L z>*Y@Ats>H#C;Jw~CC^YwVcjL)d;bUt(=w#(JoNd&fFA~z@=p-rO<6=YnrEZd7A4MY zhi^w#`em^}BN$68fek>+(tlLeG~tkoo*TVfJpDLrnjLWJ4&?zU)_j02OspA1ZLlYd z?{pVDQ#4J=-@oZ+zfd`*n_w6-=0!wn`@L;5B8zcpb-Xm$+1DJ_>kEp=3MA(b1?2}t$nA@s%U1Sqm&fokP}qsE;yLi(*pHxB(JIjuB@_L%LoO-2%n z{%YXO3Qu|%;xBUl+xl{YCX0B=1PI6HVmw+Z+~j$L=`31-Yrk@ffikZ&ws;J3FnTDt z@QPAZ6G!&=6ihZt=jn?M-N-gZ}QRH_z(VR&*d~c7KQUifPU>?kQJt zQ>H9^z1+hmxrd*@%@T2Z@>2Yy&8Qc>ghgx$a~Ra-1N~)f&RfgVeYhM_jQ!H=Vz78p zQw5P2(IxNojq_|}boA(OQA{lQjJY;~yRd=^j=-BaWaejBB%uEv2d22g9mSi7OK%kgc4eFCxC-{I|5ak$DDH;Yy?@IyJQeRSZ0 zm&UU4{&T`n+r^SVO-vwW$=3{VJB9{kQjXFTB+e?!sXgJdL7 zdj=>Z#R|(%C~iV~pmoSwkyrCHN|ad{$iCDRd5!LRjaoJfWfZ7}L_Ji>a7R`C1@mr} z>5J_&LDI3?fFXjPGAqdSyo#`vn#eds?~iBEbl1v1HYYqjNOOupFu6tyK(_~pBVN$f zxpCWT*uKeDFQCtaWFEaLG(2@CT~v^1RFLu8jKZ9-Xfe_LT$ zDxiOkLm_khMwvC2Zj8bXNQ+nY7d%@tPx*4_HMD;^rFSstV!J2ay)BPbcS8U1f>W|y zUCv+AsrtVUpAo8HhkXS~)e^0b*fIN5Cx%2)EqVpCuKtB8N{-tzsOJ;q*M+^NHhCm( ztrK}^oXepqr=Zzo8C&b*)M)JfR09#1WULsN4hoFp#kL}^pR(C9ns?{lb2#R7Zb{)+ zF)-ZJmm5*;-#<1M7nycV9clPcb+WYElBsT2vS-L=)kHIuO+*Ff>t(5MWlYxwxdg@z ztg@^X9j67fwLb83Na-Ejp8{bTzoy!a%!w{AqI=`g2jp~cQH$II$(@3)b)h9zLp!^V zHvylR>WSHOtB1NEPR5&FLHStrjxi%qBbVjMh`8RqaZ5ZLo`PJ#mAg zQqES!iow9AS5C64%q<=%?;~ULFbsQMHSRwRVT0~H8N22TNl!AVdVq8M6j$H_RJk9%%%4KDPgX_k!j&L8)xWLAOzpq4cT3J8IZP|7|IE2@05%Vak zvC7+4I;O>F5~7q`CDP!fvM588dd&AV^;Pzy(B$BQV~Sq?EZ~aaCM&AZ1`oxhNNM?* zq7X#*f@d6y(M$6K`iY-^mIZTOv21z-X}?KY%7>T)&_4UG;}VWprk|46l@8PY)RUED zPGzPcu!LmC%m}2!xt&t$U~m>RW+~>hWN=hSrnLtrlvHMUP%@*cjN(bro>+O|Ya0DL zf>0&F$o2*p+$iCj`^=|rg2K8z0U>{yx4i=KfK!K{->Z86WNqG5ZtM0!c3g#?>vZmZ zHNK7%4c?79JGX;SX!WeTyOYF0OeKtj^|7^YzT@sAM?P27S<;FeJuEnt`Z9?e70@LD z`Fw0j!kz1Ja9ObQ%lYyOS@5e7x>$A}M!wO>09qFpf9=E!;NIw9plfwiYSDM}zYOAG zmKuaCygWj`o3qAo14%^eiOOyHf6S$){vJ_z2$Kp5=1{h14L-1@5!vv&>m;w5W6KolE~6Y4We+pmS*cR6l!QDHmtCpN zR*VupnuwZH{?xs@OK&o?Sn;aEa0jIm%|sj!om%+JWh6o9;2^2%fT?43>FL2)fsQ;e#<=s?L;4?xDL!r6Sy3H}sik%wK6 z=-{=3q6m>_0WAAM_mk)XD8qsDlh6bxlLGRC(g!R{gYxUxmjg(e1
  • 0C3ik2S_UZ zTCtpHXgUev5Fxk;wX27^k+yHVBH8E(7?^w>K5BTbgi zNWg3yFC?t9y8LcloUF;}r6~rT53#M95 zWi@WfDFO#N#B}BHL*TLJ!ohY^E!E@Cr@DkTcESryLcjTFIHH}SNM*$vmlf7$iV|Y) zcD^o+kMByvX^)->3p^o`U%e68;asfFed>tWdjZ7-Sg2O7-+L3i^)g7RU1g}2yKFrZ zTy@m~tWoPdg+3kdg_@gs(vZ1WclP$<+ssAKvftrFS5<_)zKDp-ssp8TtgpI+ND`hb>indTP z92nEn5Bn~B>{?w+D!(SmZdnf6I~~sas5!IKp0?d`4BxuZKjU+%t;9yxSY( z_~iCv^RZ}tku?b^UZ#=yhIzw84Z`OuezlNIbkjc|s-}iz%u2YQ4wk4~Zs;G5okf z%bPk;I0Uaki`$4@j_8kFCFAJ%>S4|y{^_Ih&8bJ{>#(a=D3s?ZT9emWBg)ds#_eeN zWD0&Peaad&iJjWj#21kO>e$z_f_-s|k5d?^HsrbGm7zioOM(`36+$>;-A#7JtyQO< zjOQ*jv8o>|;jZVsKH^P^Uy=w5OgY7ng9Q)E#ZNj*bJ7KvATOi;BFy!4|7%RUg}yH- z>i*Vw?_~ba(89Sz1#|pH4YKF}H=YvfwIEo3~a?bVXbl?=TKNtuMcGseZbGo z&+7M${r8}J_jI1&r}?aM5;yO1=!Kz%$^l^Gv)>0W|BpT%!0n#h+N*91Zr=38nfC@9 zUgwm$vaBn!egKXd7ve`L_$zbP)w0-+9ZDr^K83A5i{%Zeg{*MA!->&A-_{kebi$$S z321B;*wi%Fq-!4|y^o@6T@Xb@LH|{)R9V-r|~wTa$~4II(7vpTnm70^$jLGL@* zZfOvpz)JYAh_tvx%PFqmZ7ZtJWvl_q^bTxPqN4U_$UQ?5+jJh`avXg$Bu7L=R`$jQ zmL&N1E)wipPt7)4awK0Jw|vGP0{mGju{GIPgTFVxaJhCB5{I=OCqdrC!pnd?Z1fEe zKl3cH_9E8R;~GoTS5Pa-u5!TRaM&;iZ3J=tbh^M!2k!iN+-N|gctF9(K*yj!-q7^C zfLf{Jk*C+6nzawI<0l#1;V7ks4(uDn1RDgt@t=?90h9T6>Rwo9UX;RPr44QztZ!q9 z3c3!1ZZVv)$R96MOWIaiUG_Hps2AQYcN1}fDvPBuEZw4zCyI}q2Yk%IX|2V73&>mzjqE<)m=}Jj=;3?c9~Q>v zrg2$?OV8pw$G1q@lG2G|q0-w2)fj1>2bq?7{4fWXF&qrhr0 zqg~zTZ$37y6G(YjQO5bqLdy+f{RxU(H`%E#vc+jOT=}bt5@K)SmqE^<+LVAQU=OQj zW3*U(!M&BT3)0bDI(Nj9^TY-Fg3%oCxzUq?M{3Z9jVEPojZ0T6{Ucaf;z5H*1XYm) zd&;v+y$t_Av;OTDknY&EjB&&FJ4?mYX&$*7F7q<7qED?X2OR~@@(yx7R@Xl>wqDJU zm}hlT$^>8_8hRzVHNliE4k1o~I(!4)caIyU+bwI1L4NJUsE!wk%%Q_H;cEFv6|_hy zC$T4`nTZb4{_Py5F1tS=skx}P{%D-^$RThD^`-?K$Ky7ZGLH6mXtfauZSAhHujYg! zjIKldH5S4IDXZNdh|Kl_EMmus+I2_w*xM)x(C@!&L3`^iua-euaj460jxQ>50xd5q z)0>+Agy&xCA>fUg+nTAPEQ3WNrp^Js-#Caay~hKpPeiQpdIk*-cj^!(Ig~&`@J>;WgAjotUV)RKKp{VCEu8|rsuS^`4XYB6rxA&-VZeRy%ze`CCd8H&#pz8VsalbR*>u{A0PU7y|M{W-aL$rdr}bB_8*o@ z6$ljDd*4V(cSh4lU%a>!ROVb57Ud`>$KG0O1oRg)P$FV`*6t(o7a_&jb$dSi`nu4J zp6Hj*2+Bq;;wsE)7jy!eDxp^nmor=LfbvH8sg4O?7JfXWaMJ6159cWww%}2b07=*Z z4+{zy=r~GXgD8mp5eV2Xqv7VUkqC7VbRc$QNpy~X7%!nKOsA-org5tL(94+YGFJQa zWhx;95A^|wG1|wXd^0?&+;*SNVg7V1g%YFGh-bO}J5>>m+ZCHP{xD~JQ@!>3gxw#3 z(d9ATj?a3Xg```&QiuQ%+BUUqo=#i`COd_uyB083XttVs8WW|^{7bQ zpndiCW8k)vQ$lFvoD&@0%#=?F*uPf& zg!f+J9P1_-l&k+uKYODj3@Nz84O3mQ}KLgRmgTrd}hO)PJrB*Q+TjV ziu~!)1faRy%OyFN*AeS_Sv7w{U~ShnBOOs9E&m2_ZZerncbBp9X#ZU`9k6LA(+q4~ zELB)k0G0knjQ2Is<$1qH@?zmYd!4JeS~*?8f)nZohtUtI!8l}^QE<@E**gkT&T`t$ zKx-Jl5NwHq(FpRIo1?7qN>$6>Cpp-Q{^8%sCC8-pUu%s3cgdnhz1s*(zRy$J48Wut z8pb_6>P&xt<{*^ejC@OAMxmK7XcY-upL5d@Dtd2u?=j0#&de&z%ozyKbe$cTKrk#H zma&}C>=+8*E>Ui6S?CLNf5c<-qSb@(1m`q|HG}xwYMH$~5vYSL6 zqaA}D2_B`Un^9+T&4P)*szJJ=2Pt<-9bh@8w16`BJw+xb;YSeM;*x40Md54H>yth) zwyY<=qz|VHxc?>3yDq&#hd~Q@QSisAFO2(X3&=FhkWDjv zGl~zBrE>3_Cgt*BPL(-;4L)CF*gPlOd_ZtuVNyaEQJQ^qz4^IrK&&8d-ny3A^7$3S z^PGKyh>+QycBfjMu=)4RuX=>2=3hU6nH(ackR_C>L2$dPp zmxhxF8m>H^kA#s>-4GR$#K2BFP}n@!C)RlYiB~i%JGzv4zAz1H>5&3`BVeYXFhXb= zugCXW5OP+IUYd-FvvI}Q@YcN9%0co*p{&l}l1{3r=k=sIi2s`;@&qOw7R3LM?8n_o zD6;!n!=EQ;2F{84I8#{g{w^D78y)gr_ZDf0yZ+PZl*p(}L=<}Iiw8R=e`#GG+{O=# z7nr_Z2HHU%U)M-2A#FXwuGh;-9xH=5^v7FL=uYRPwh(aX^kH9kamST%T6+&AHA&C? zCU8PNdk-31S`4#LLwLA}MssKTw{i|Z<3L(S@R3RP1)$$vd>5uY=j0ZpzP?bwAG+w- zE5;4vtsZfB+!qdu5AvNhU!Qkab6tV!&37A4_|SV9gOjAHS+Jnc1z-dY^74u=Uh2C$ zv^FVucXaotX}59syf&(PmEoVS>{a=Pf~$?*Yy>Xf=b7yWAj$&`=f8a4EhZ44@$lAe z5hU0Lb4g?9sUBL<`-~7ahCn1!w0--zb3X5ZT-WCr9eX-7rg}HaD1~%R)G3&BrQ~Z@ zZw4-du>_YxG#LD`N>1)~ArSblcEaUBgOMoXFAeCI^KRsqSBnUi{y69>C%i%HQhM+X zvVgybX@I~d?Mp|GxB^`jkcDKeGT5{ zyUp4a#`xrZ)NcMq6_e$Znq#?A+|lh8u`Q@KMv9=Ku|6JT*Dr9H;4ayL*L*_P82rCR zgp1TuUrPGlo*#kt+fOuo@uLxxPNbYV^Y3_ zw=|RALU%A2PSi0k8$ux(Dr}t@!43ed@SE`8tgP|yFSuw3_K_@yq=9Zedg5(ukJfF@ z4P5BOIZsWuPK4wbW(+1jhsFpnIZQOzJffkH@AgjifO)= zCN*{89-q$?yubLAY2L#GF(b`Bx>U}bmL|VdvqMf=wHLC5fWGjbG#l9nHgj_iVb#iz zE8;ISMGT_r^P|qSN*=YLS3jM2_inS%om5%>Q#dz>0r76!rI1AxuUn((u39LUk5t@l zKKyzOzoa(Nm&z7&ga7O6L|8fGb34wP*eS~I)@&ZR(LY7)XQ??*ECHVDR&qvhUx!(| z;IMf?R{8pma|AZ0d*S?oKN?JK5<^4!b8)?Ju(N|i*=1^NxhboNLaZ^pmUaG0R^X!9 zKn4T7Comw_blU%amc~qRd1(5~YD{xBeqh-V9ESa}E7i8-hxZseMdoH?`+vq|Lc?6# zA+!+ZLM97h&+wVM>Y`UM{_k|}tums+68o53-4Usq)!}9 zlZB_4Xln$y-W?Ky8zH6o{O=xAt3@)Zuu=a(2fFQc;TkRjaymtMuqk|LbLB(aZg)0k z_Wz+|_|$gecD`jGvZa#7KiV=q{4^`DIV)KQa9EOhcqFW!`9CP{1p3U-0z(p-&BT7M zsABj9$2pkP>afb4%}3zMqN9dr)!?+A3zp0ZTRfPos8ea<=m+4d^8lOtf5@=-&UXZW z;lLs!62eiQyR~2=!8)RKHu!v81>%j9=s401ZfD{NqZz^AbF>=1$cN4IVw-e!%fPA$ zGiK~q-k-r?u>PgF@V_*V1p8lUPQ;5AIL{aH{|4sO{9#L9UjBtB6PL+^*vp<5J9QGm zrB)YTuNtYn$4IxZ%nF?m{CJdi&h2a=;jcHEAqy6(S>1Z+`$2&Y*XF9~5|S%>Nhxdx z+GfkT4z0o>7wJF8I@RY(Gl1uIFSmP2tp^^v!FSAh=*~*HM7L{oqWn))h3lSmwcG=o zFS6k$)%^cvq_B`eP%+4wEj_{zA)rr^)P~pZ4%{(EnKO?jN$={7N0P<=19J|l^D2yA z@LGc@E`3(ja89lh4z_)0gHQz~E}^{G!tRqdRa&q#?~yjTeRpeyS3Y)^o4PjuY!2)r z(+r^46B?EcgMzADm|^MlGW%a-+WLXHQ0T8Jzpyo5egf$y!V_r`>k6tY8Q7D_tRek z9|XsT!RC282=u<&_VfS7{si_?&mBQbH)41nBWdPj?6j1c7F2$JBVuIuU(Y9%mm%;I z=Lh81R_|S--Rs%=eSc-D>FFkx&&VzbEQk{|^zTJYb-3^OXx)`)$2mrcrDjYa?}F3f zLba&SCmA;3XI0~tETp@Wr)OvMR9y06e*UhoXV2lR>F?)l@7JMdEdK92Q5Ph7|M1L? zH{OnjdRs2Fs?Wu#_($vSN1^Z6-uxjv-uEkQ%P+ehE$`ded?+^W+k0q#;qLFH@26cO zZOGI8F5`3e`}1zw@AL5DFWX0Iqwm{W?t-q@x2f+#s4vgwB5m(a!_*I$K?pCgdq2?^R{#K$ro$& z?dh-U!+Tnmt}v#*ueU?SR81qgCyDy8JW`^26ND=Z&(2#~mxKaRP&+&%pfuSdiS`Hk zxXQj&WEC2r7=rkqds+e);k&Zf0H<&JK!6+;LP49_fcr*B zvG1vN)oC9HZDbEbX@^O))#|=<8tuw@GJ2IFNw#+NBSCxgAC7AVb2iC5!`Ch;lv!lk zcr6blby@fr-R^rhU7wc+gv;4FPrN4DSHDU|rCr7eJ(N2ykFS%bvv{m321X(({Bz@h1Z(JH7rNVG1LmW4kBRG@{6kHGjww`5N@#A>pVHbD8Gm?+0;_a5Se7^kK`R}m$~syI31Su`IiHp z&nemJAa6Kl74fIFn2h5nm7q^|XVgF~GKss#FU1BLoue+Q)(8ecMpr%7QvB9MsW^2P zg4?@Y(nAh%!~uI~D#6NkX+R^BbjGMy&A45n*8LTd7Wj8R0A+=PPNM@IZU9ARjbL8V zqK-#XGb~L=JFa$^A2%I!BuSysAZJ{t!3)9QdzVJd<6TT3JwxBY9UNBjvJxXY<52~H zaR-^yPJvj?hm$lyGUy;eDDdTU9v2C1A@yK6gCyD|=@hvyCJm83OTj%(p+smpEVSBs zasdld8vq4kT{OY^JkBa66?rf~TZ!d4F^6pW1&az}y+Y2>u+^TlkWar51plN6B(7si z%^P$3sr0cCf3sZod80G%KDD=1dWJH%@r1u4mDby9@tJ3xv7ZWO%_WwSXC2Edv{p}- zR_K034Xkqsr`r4Rf-duzo~}FSj&eR*F)j60KdhBumw^wzZy5^uQNP%luQCSYkvPK4 z_cM`iz=?neEFzCQ-@3w}K&5QIGM030Y{46>*vo)!wH|?Nyye;qU3XDNl1)y@y+^&; zv3WPg6X8E!Dqen7XyZ2xEtBkiFAk7#pJAU!;R1{m|Ef`+H_xKkh~CvY28 z{14H1+A(?e0blNAT%|FUmWA<(e^J#TSQN5EDID0giRDPxT~etQ<-04@eR}HN1s!t3!2t;VJyK~(oKXPQ4jEa~OAc?bU^52T2rpoO)1$m_{m|?R{ zVrZ;VBNcU(=~kfF7yqG`z(i}HxNV*}Yh3tEnjerDw8 zaKe*%HXU;*fwn0m=*_^IEeq2}RHC2fqI#kZJA)}fc9Ja=9+F6*ZyAZPjJh^0P*O~4 z*lGERa%eIvA^pR#Ib$Er7RWK%gB08{hi>HoX}#*wMjCoTfe-=Qvb5|zGId|RuR*+u zYdNzfa1(I6$0+BOpOYAU1%K7P+>PRCQ#c{8x=TtAu~K|L zl0wiS0E3}8wnZK2YS0@&gHfNWllGtIFOG|o_wO*Yv z6dHtD!C%lxswwZSfUwHY;%Ho*teFl1kblcy!mDXp$MJc4R60%aYUFAhPQb1obM$3S zfs>#$pyKh8t!c?`3g%#ymma@PyG$l+MK09(prRPbS5PBiH}L$Ojkl)y`W!}VW6GlH z!CyY0A7`K>jq;HOyxqLe-%c*W{Oai7MD0J zy2Ub%*8(Z>5^GfcauoPL=!{J!7hMVVsW%g6Bi)qdq)Pf3+B*5&X+>sTcYt!rN5y8k z5dy(F>eK~Tf@S)%8Dnh&$~S+e46=Gfk9`Fi{|Gt&fBSCzdcK`Jw;mfRefT=#I_W)r zjm|lrdj8(J-qSM)ZZ1b@3+}E=hwDo@d74`Fy`2qZYu-q?UiB?A-C+M^+6kg#tt#rU zY~7ROcmD`6~TR};+vXd-QA}TWaiu^T5=#6y*v&w)2#Xm8Z&3g_+j6; zJ!1cGAJcajkAdqL2juaY!d*K+*A@uoCYn7u8ga?ax>8(&$%pQih>rM!5wr*$W9P)_mW>|$FMB9jyZCY zk`(`U(_DM4zcK@?vBpXsqK%xuB8m`shH)2s;k%X1pAS8FoEr|p8v_-{a&EIW;lImY zrc`F7wn4&6Et^Pey6-f`Oj^%pP(mECdP>u_RGiGF8a-lGJ!GQzukhxO+s-$I7H@0b zX%1#?s;CqFDksOy8D~D2WGXj*ULh%Zyg{xI~HB_dl zUkN7~y#I0#ZaQ4a*CtdYn&ISD8ku|%kgjtCs`7D4V|Qd?E-02lQpRQ%fq+Gkv2t#J zM@Gy$J?R{V{As8`CPQtS=S>^fvdXqEW3zd=6z5?S*1`b&WstfgQ!mRSme0r{zo0`w zb*(D#pr#MaHmGbflw2m(EmI!7GlQ>lbi)KR4NE~$P57{HskolbZaYwPCZj!}jJYzw zp~;ch7sXXf&g?9fRuzK;MmvBJNcQGv0c+OMqO-VXLpBi0zvel!&|Gw$sI_R`HVt6T z!$wq~I@6)tM^cC-m)D;dDzvc{AM8d!cDQn}FPQffzDk7hDB2U!mURxXlLOX<;z@xP zC3hi)G8d3yf1=B*=cgG)PR$U9z(m0Y2b0BPD zGVHT+0a2(RP=>~Gjb;+qPjZ8b^xsU5CXhqTDW*dPK`uorFBxb=Z2>gRM}RLIa6n1X z_AVmTucxwWHGQ1~Fa0AU1-V81UBH@$$6F$RODRX{!VdN^j*c&>_>M~&*PI?{eXtAI!oHTlK&952q61x%f4Qz)+3&R-{c`R)?F#QH$65uqoA{|s*UE!CTANrqn2s2* zJa&HJ(>n_G$pfKUA_VLmV_5hDaIRZLWcV#c%>&h`H87qt&xn5nO04i)4JE)jtha5* z@wU=fBqA-IE)MrqU1Tx#ZT?wyW=0o>{JoOm1)azSl#H2yrm&n9W2>%18uotvIhMj+ zocL(VeC8*%2Hw}eyW@9mCaq)H|4}dL63RfT_!%^I78$4bp%!t%yP!!%7LbiV2{Sc8#dF ztQg~!W=Pdt;8ON6PCI58rJxE%JM+*3-cC?iKs=ccX0#B?pVvZmsOC~{M1?YYd_3=A z3)raN3aCjzD0$NGc&jQIQv#ex3y}qSzn(MZGR@%Hal-)&HO!4spXI|}HR21%tox2j z7KiRNU4i()#n#Wa#&~tOFR+QBsnB#lYB0|ps94kdvnMw&K?=qIPkgDrQz;EdkIG0Z z99Vf#CPwxY02NhfI%%pgH5@rQle8|<( z=0XIpta7174fN+>P{&G|{kc(;Pj~cMeA#q4q=2be8eB&~N`UdW^I26QoGl5(uA1~~6xiQMU!{>0Z_wo9XYG=xVr0hMaQXrK2=tT9v28jA%dRv{}ht9ag@dTpb z27=N;F2_dsz3aGwV5;DK@N_1;XT*w6Nfd%(1<~%J8v`PU9mnDGAB0mH1EJ5PQC=4n z*w4U`jXf~YxX}dv78c*Fxl*)-hHL!lHzf@ryeH)Fzv{swRJ>q1;h))wC$PU2&%vYO zC$H*Co99hAdHl4i_PpL?FWpDaF^C!h>o_nYJXL1V5+{e&hwt`eKrB#f7jqu=(??~q zT7F(*s$$#0m9*(ss4Z=kyb3QktmA6yar74bA*A<_TT=eys1(>5m5wiuHkut~MXhnl zR=O`7vGb9Y6)AA%9K9MDzw)3SDLDpN3#4%JdWyd!+?xvK?=m;#7)fGXj7%}eB15`+4I-bI3 z*%O#^dD;tgH)C}KjGuLfBFNW27sFHC&xcY&hZ;pO6;czC?nKC-^NB2 z95JbTgaH18MY{0cH?n$r--Lr*x8b=VApcXJL}H6^<=u+HI_KjQ7kUv7J4iD)(q~UfdM8<(AY&EK~XpSEwPa!FPO3Gj=09x*$?_H zDR>+QIkQ$XT&d^E%L1v>6sPW;!f2!6Ey!uPzXReypSj3rbY=7|C(8;QG^XeQjT8be z33UKgEMg2r<@;t0+<&j4-mY;^csWV_6x2*@)*b>08hPlNV#dxQdoWs~rYbl#lI|-n zddO_29Lezi08>D$zq~Mz;`dtKjlWojm@6FF!l<$$#gVN5nEJOAu1L~Hy6zUqK8zNw zc0#sQR$)}i9=cwO^D9{)g@%W z@5``NrG9qId2km7v{Q>PuJeT*Wur*o_}BD9mnhW>L?x4}C?zZ}k5fX3dcYBuFODoR zvw5D$+fXY*1@B%kG_l0H_fLwJ6dMIhWQW9!jM6H`0>UB7bX&Kcu^_7{JrQ|E$}^0q z_Kehz9x$cr!~oL^|2}@Dl#2;QuhZA&Eo3H(0M$Q^O_6Puv#wcB`%0pfEVuPGM_nVE zj)NMR;(;#W3zp;|7u(dEZoHw22&(FOkJg<>ag<%b1eJ8hakY+jWL61{>JS2G%+QrA z8;;wGOL+JB^V8$^?&rHym)(bGMKlc;`)XX94x_&Pd=e<9MS%K^2x?q+$MyZU}t7e>Hdz;OA=f3 zYZ;ZavAF5WW zulJr3avIaWr}0XsU+61O>{}e((l1A#SXt@Mx1TRpVC!RtsUkA^c@UsXJ+L%; z`;Q7^qncQS7Y8jjxGac~vYfD**G>o6y3bb1Etsh`TMf&EG9P1^g~hV^O$vuwwS0a% z@MpLvXPeYy#4&8XY`)b_VllK;bA%$Wxu%|=j-;+ycwj_t0LjjgX`zB_Z$a*QuM^?P zRhO#qV*<-8W~%#e(5e0+hdy=vl26grzD)fk*}Esq_NeJYsKin=%3iW4>Rs`An{2!H zbh5F}EOQH#6?J?}h-=aN5}-Nr;6-=?8$aFIF|>^%48?^BcN7MZ4_`<0zyp5!cX+Js zY@9HAiQOzcu{BnNoVa!o*F#RmV_LNMzSH={fBuRpa$~bl2iE_wcO}pPITAr)$hG}_uY5jtylLtss1BkPt?&FJRzuZ5AA=t zgF{nFq$sQ zw}>yAi22dM;|kA_eVeHB3?SHJP6T_|7Xe{)*`6at43sAM~6KvHl}j=qjK4jYjO{t9P33WOwu2hrj2hqd`yayk?Wkt4A& z@!{BnYYG^ovoW~@uBS;*+86wd4rl`yMOVg$N131=h$xDSspmI}t7uMB6qj=-3d*@u zCwQ{x;KW#pv)aiQi42*J1fw=M2()V=QXLh|M7U;ah>3WxtHwA~bH)19N4;q>7^!E$ zAX#)!h#X`;H-zE4lR(|^A%uz*4T@q!>O$}xz@+0=Ggiroj1GDg1rXYhkVvBdu-nfl z0PN|br9h^D@Q1WSCcpq4B@F$9Yc)7k<6{skr9Bo2oNS1x0bt9V_B_|%JeEg>VvMSd zS85%l8R$ClMF~c)h~5H>7K^ecms4YDP6KKXYZ^(Gg(pzM!2Tixdou`+)`;M51(Ej+ zg1;9=em7KohrON_8j^sZ|4cxcFhVp~lVlwa4Xc_ujE!Jy9~h14rk#WEjbRA3g_(Sy zlAtMPPgNB_Jll}SctrEM9SIa|IIbN)l87KwjKIRs_yn(wg=2!zq64P2Ty(Is=8Hbo z*nLh0Z@o-M+eUUpa1!fxvU9+KLG_M&3gyX|gfP;n1wRYiBr%C(jmFQT7%fHtQsU1MT-XQT>grcJpV~xO75~2|f4U$Iz4Gtj#bIHNcF$sYra4i}i^!VmapoxJ5AlSR- zBvn=oW)snIG08^lM(ufuL5azeEGiZWiARZmUdHtYrBrANVBQkr@~GB0I;jFsi%1q8 zZ3K*gz$?MzBYm=JQivrTK{@~dYG0GmclD**fp^`lUgFisH~q%{?3QRqs~1f+3WNau2xScA>fw0)>s zKy~X(1EUiUmg3Af92X2zYoc=am{1M1z|qzLd#_b%va7nz1U!C6OoHq9sYtO2)1t9k z0HQamY<^US#meHyq=y6?BL~t6_O>EXGBRDSS0*?yRu0~`4gpOtjQ|9Ci4Ti0c{yNY zb*Nc^sFJ7A!tnI~okvXP%zy;SrS za==;DE5dAFiBSKmMDHt?qlea99HieRlHe1Dd1-VO+rVgxZ)m!p*u+5dQtIWaLk%Bv zmDnIn#n&BRj@2g;h$Q+{dOt`AKj3sazi3Q#6(M?x)TNi0pqb;%+)%LcY$z`E8&On* zTmmDPt52!(9p}{kpjk4hNVzVAuEgFL4UZuba>N8myp2}d9nse4j@ z@Ps;yLgKI#8jMOFUri~{ijS`Q6Sr>7H9AOKsAeT3`e4mU24X-Nx?#;q2_joHFr|9G z32M0@Alt1xMBABWv^B7Y5)EY0V6tMiE{j(=90?;^j|Sg3qC=$ngG!r-4b+K1J+>th zy%C_F5f_O^P0HXz@KDT5O~kF!Sj;ajYXBD9EoF8Zjpxd&OgdgqoQE$Ii4YMu#A<_# zV_=bS3{5hQp-sk9lZyEgK9@kO=bu$m<9mLzt^9Io^;{ymCjNz{@WnhWOVY=E`0)=S$UJi3~{K?wCH8?)Q4_~U0Y`>Igm zb+RlWD9kKcpL8R!SR~?#jYY}=8;K=+&P4XekOWoCHpgBdNgPEYHLyJ$%R5iW$0NqT zA>rdsWK&1UH4=^=y*x4Z8QJAQxE0MNc)f;cLcUR7pBPjvI^H>GiaJ&ixIULB(roND zIO?6e2c;wivLvH)A)~BsavzjSNbDU$E_jQW z#Hd3gltN0%`o!-9Wb^{VC-1#_hW8YUIm9U4BwPZD-m70oPQXRqE`flA>x;s zrDS|!Ba&Iq984%9G21B_qlAQ!T6Iykj+hLQgiEODxqm0*I?75+lt{*^8GHXy6n3$g zYY_E|gjPHL{)-$cC>JrRJQg-GZHcpm8$--L<1-( zF%Uf&se!h}k1xvgf>IKL(UVacXzMRY{(^E5L(!9Qktvxk&ISWG>4io_re;*S!1VMm zD3_RCX2kk3^Izt5K{<(;hR8T6M219&jKmuj1BFM=WgshG5`!2WC&Zi^BwQ|NztJZr z!9uKJX)v7(K9uYxO!X3-p8WC*CMXv%%p@5XRS(uHY&PH`2JR){GU!3gQIC+Jqd z2N{Y*|2*o-ySlhrRz$VbwLz5C<*a%M_GjRZ$NhA<}zo<>Z(fzAFATD3TjoF#nf=!}jP^ge z{^jt5g#PDqc%rZU-w;Q2=Nf;=aU^6X8}}kuacKkV_OX@T-hU@863_1Pjc=KtxkWle^fepw6v%h zq?B}L7H9pQeDrSSXrI?JYX*MgjCWN=UWh4~5K_hC4X;Q~XY`ENUlPg8$q1Y}`?&R} z)n%;%j>KFj+uG?=`0}^%>u$Z^PzX+~nF)OeTQ8XSc#fNUXx6?`Yw?0lvKtrur|vnL z;d=bwI9A{>=Yj)+J`7AxSB`norEP}`qc_!Mc|BfQ{vkSG$gdq%%D0!plbuT+2JP*t zJauIdoc+GL>(aEDyQ@xHls|&@jXam>&@c7xTg-`bHpW72*l0kKGduGCI`eIceccJTG3x?cF-`hV)O1TZVm~5h*0y^G8!vEu%irg{ z;6`pU-}{Uybq{MRAiIi!UU^K0b+OIodp*nBJIzen)TR-4i1TF!CoXUp5(x!VC{rwiXb zxp#VEO39qk(0v!KwZCfX)nVEEgjO|$13tT7%NxAx@=tpm=WOg3SK6)}@*&T5Z0ii0 zA?#zL4bnV^z^J0kUAMU2&*b_hygT4?|;8Zo$yOUd6RA zgnwSaP|ftL76Kp3tlIRy(r1t5=CD@Y%7R%IvqM7?!sdp?a1k-W%?_5uC5J~V{|s0% zpu@$;3-(@5*!le`#yuRK+4r{^*QY%b3QEQv^D0%e{JHS_n{>W4?3l;&NN+kp+O}=j z%sKz$w)=Zqljz(%Yo93(uA5a|J3Z>&?g%&r?vdmnRd_73=^kd){ny&>5{i6opK0Bt zhx@~yawm)1RnMGq`P|Sx=)JipWz0Ce)22~jGo{zF^SLf#=iaq;`KR#~e_kmB| zTvxtNW@kobSEyFX(0sh4?fOD+R$V#lA#J>9!^$aA#?BT6y8_#L!<(P7N4WYnNxkl{ z=aUoP{kN`38-22>TW?yYXnwKrvxVOGD;W+em?^dl2#z{n{gKgH=`}b4hO+xJhPy%O z%C4zR4}FSza6QfOPuD%Ng9XA?ZIee=N%i{R= zR-#L;ncc8jcrr8}56_M*L|j%@ZF%vW4Cr}822;64;C>)DyVP-MZt;DO@PD^j@bHgTV=hFbU zQm1Xt9hLA=R0n-0opB_;AhCsgx1W!nw^)7Y^{*ErlwOgKUnDMCv;42!)r-4Nx{Y?{ z_6Ny5X8EmZ8ctJ`xmU$#nycso7{``;30<=Q;1t3B`pS?!P>Lzb9j;{i?1bY%M;8x+gup531*RGNs0;t@!j!KTDf5 zxHaSZN-s;dWXqu2GtaOYoeo)&R!_ubX4OH#X!RD|jgT_Rx!I4}-~8L#_PnKENY}Qj znIErAEvj&Cll1=6m^^on`w@y+tv;5`zsk!8iW{hJ`1FE2uM=HrZbCr6D4rbZbTum! zS$;F^!QkKh2X(9KXLmw;nE(0*XS=e@N;W(lSNTA}&<(aPR4_ZXuCV^descBb^}7QU z9pCxRA8@?}S~vVwRR6FHpS9cG(`$2mz@V-WbkORgq5ffH)ur14{j=ylM)c42Q68Z! zU3!k>4wxS>>txdOKLd*HWSmKuwm9#SU0_Y~1jWo?;rNon7LP%P7dnjScW^1=Lrmn( z;>&I$MI{57sei~1KiwZ^d!uH+w>fYLrhm53sd1fK_mh;7UiiM_mck;>UBOmAJ-iao zJn79Q=$iAf)2$y5>L#ACe&kAJ8o6jR%BuDF9!PE@R5X-jjI!h|U5Yn2#$RH)wb^|< zOInm881L81e@RN^&4dG66n(DssA8W?ID;xkI(db&;L*~wtxO=dt_8`p2`n#xW5K+X zz?h2V*>ywv3afT~Q-1x_c8PcQ{iJd$@Uh6MbLRuOtpb%R_#i}1N`{}CCu=Wy7d!Mx zx zHYOi?_`t8yU7o0@P$XBJ^**w35^2>XwN0`%22L zIq;jUE2b4(R)*OK)`bpVS|#dP_2U~w*u|_hMQuEKct{KA6ct>Gjj&UPQDI7YY6)t2 zq|kQN^gj7JPQHJ-niDbVO%VU>y%QZQigtBS7A)?+Z#RWvXq;6GpYf7Hw&?w>8RmQ9 zd;sz+{Q9jo>mj=1k+V9a@6Q?(am}UphnBf)BP4k_rETg zezSR>Q;*ubUM|@9=R0Qu zUv|jZ4o#5!T%LOJ7H)lIo`rMi4Xj=k7HPp&On5_^rcGNPFE583Ez&MGWx}y`NG`*{ zf@Z#k84&A@Re*xd=79^~PDt8X785SFo0khaM9MAw6q06@fqBe!O6B$OcitcQPv6bo zauVOA*e$DFj==LFR)FF|xRSkY_-}E8)_g9SpYZ)_``*!?+N^)MU*cJPcJ8(3OW=9e zYExluYA#x7x|tNtu|L5?+g8z-38&a23Wvyi%OCqMDZF3kTa@)YWp2sgz|zi}-0F_l z=Ny>0ziFU1EN9iQ{+QO*;?&D6!9#;D9`ir7c>J~(c{iPR9^K5U87$59+#;O8`U8Sr z$r;{q(5TgQ4F9`N&({gP3i8&q^M(9Y4?cZx!r+0H+g-fp9C!)8hgi$IW>1qwp6PsP zhxOYNRh9l}t}ViCT>4&GKK!ze{fJFJTy1K@%7@Zl0|CC=9D*2NesO+qC24M#0?09f*=k>? zhi{YB#V3!>>anEdc9~uEkUIh0?AsGy5U_n$2mNg-I2BZ z5B@OY*|OoWY_EA4vYgt?^umA3u7@3AT9a`q48i%i-yauNEPg2MwtUy5lyci)Yn-}OB)k8zbRaxKd_?Tbv$L3R|T@Hs-48c&%5}KLc=HQ#R=T|IXaCI)+#XppFUfiADe!-| zt)&02@ayUMr{QFn<@9zE{1Nt3I(u2=$IL2y_3BtyiR9YqMX3X4-Lv#QDqrJUwnAyw z=%TW6W#pEt-R%2KRa}a$Tq5os=PvEKQzQ=L=9$cBnNK!5#WS-}#C?T24nBn4@=PAP#3L#~t zbSsohO=h8Ftf*8}%8-yEgi5;p=UhW0r|13Y_xwMv&-ZmqwLO@# z;hsAIFlp#n7T)Q~a5}diT!bx}Svw>$D!k8y?IsVzJM=ygbe#k^0ba)vzJUa? zz~93O&yxbVp0KZu_p6Jod6s8o(WHA_fTSyJAMDui=A!! z*=3cwX|%`BlVASa(Y@6~VC$vF$FKf1Hw7Px6nsrD3_t?pkf(V8h;-*2JHQ=5rlM}( z&~(y!2TPJv(JjKlBWhGR*Us8Ks-~B|R3sA*TqWNL^as4WI-xe{8QgNX@%*uB7ky1J zN#QB8;);r|oZRG=e8u>F1bsglz>5l1Cnf>BV*3#5+2s&K+fYH(;NK+VeIUN|pv4J2 zK>=RLj7>qTH>ddo{hdoh0^Ew#Laa|8u7Uo(3*Juz|7OwdZiYr3ng|+7!Lizi^+Il1 z&;z~T1I5r6f&zV@zn_8kk3fGbo=XM)K0HZ`xC{Mxk)sN_oebWt0RP6tl;k3Ko!2R4 z4((aTe1aLMUtgP@@?Z$nn6fG5$f*Efy5k-ScVz%sg!&ol$biVBlaFH5n|%~ix6=~2 zdhu(hK2AGMkGrl@7rc3!jw(Kq*f)}Dn{(JXFST{xD zwuS4Un2mS`hd+=XJVsi@i`F^riQf&X@fhRsg12&JRb3|{9?rWq}J|fr> za_f?kD=6b3$ zW?E66X{@||qk#Sa*#-8S=NG|&>K!*lo{4ncc(r|t7~5V&t8QjW!;ZVEB^e=gQ}Q|Y z!~hEfG9?<^gi)ah0_R^v;bos7$(%{DGJ08`RhY7&F-Il1rlT8+D)3y?Tezsfbs*fC zF)zQ4z4KN6hMmk?hu9{zzHt5Q6&}eqn^|}%K>!#)CUMsWC{|c+iKk-9F6Vk!d|{hy zZ)sj)W)!nVaNvCzSLgr59 zZycZlSnC*qZ;KLR-xkZ~U1#p#8+rjls>x?zkQ#DHZe%~k?3Gl(z{=ZdhI5m0c2Np$ z`pl~ldQcYsR<8qZaL!2G$74j9v2FnHL2z$}-d4Jtom3ug=OsSlaf$Tc_ASnOT+b=l z-=wEmC0+hP7g>R?1q5pWcY${#2*iGJ1cDe+Zu+uO%&*xe#-L%ht{Y}p$Mj;%te@w@ zxX}eZe~l(u9|dBzDQ~|=G~{OhttD?Mh-&Xa<%3mQxVbiVyOKnGRn};8s-A8##rNe` z@gY-<{+c-8b)r1(#uq|GY(Sre;K;fx?XzAxs1t8N9B7&*Q0j+N_lMr&dM1!qe)FY2OcOHU$ywOm)4ET6rezx!LK~ROS82iPI5w z4{LgdM(<)IP9qK`e+Co<`4d6e=R(W0N6M1S#nEG5`>@uFml&9T43fO)WJzbG6nX&*iORku}e|qee+?Gx-f(0-8HtEbP6EJ`H?9aMVRZBbCxF zZ{o1bSa|*X5a%_9?4-)`$FdAJ%F!qWAJ#*AdgJQ>(Ryg+9kXgQuQk@hXOCDb@71gy zDo}eQaf|J8+Xklh0BId3z>c6#4v@*YRpY&ZCCW?Yoq*b4zB$EPuf#m6*lKzzA=?Pm zTli$~A&@H#XlS!1*{64%s<~9tJ?3ZZu&^<5il4zE<3L&5^Or|WBZ1?{WE`Y{fkc8^ zuUIU=6RdwFJyxZ`vc;hHoydpgePMOdDPB3T$ELtQoYbCgdNR@0 z`#h%j$)O8}&=e-GCxy&a?#=B>e&v%BJp_D0AVVRQS>~2^iGwjiO~O!IkZP907Ka4e zFWFCcG$i9aiYmAyAUewvsmnuz$$hZR9O?OPiq}5ZYPah6=kY@fb~{dHZ_Ic@&wZ%9 z5}*a>lY>P!`PPOgKTlSxM6@0ELOyvc{9F<_9D32gJ)G6m@@xf28K&fD?*Yb*A3Vn? zdvf1AI;no>^{o&6COYP`#BE)2>SqKT+<|IM8R5f#j4i4-H4Z>@FDB?&N!= z7<2Y&d8M_e1^9@r_P`FTbBgms z<=19)iC7Ogl+^W%Lz}HR0<XCb2gvKNuZ*A>~70LC}7BL`2`!?|Csu z;2?*r(5-8iZok`?=%!&#&YbaBTte63QC~iA20*4xU;MwMp~A(W{yhzq*MNa~errn; z6=^-^;8wfYtx>q?OUF)JJIbRJGB@L#_v8ey{aZZjv?B64)w*$gqcfPfi?K&`r^~k& zlRwcz1x4bYmC`gn#S%WQBoi7q{m(Krc)ydAPo1^(YZjPKW%`wIP3C=c+Zs74R)42I z2owU3hz#OGg063vFuLGH{g#Q}sa~5?xi;Vu@6-3_C({w{)PQT4ZTPRi;{S?YFFv}w z>9HE{jN)U`?W;R{q5=eE3wlEoq%%X#AZpEe8vMQ^8~6pkuK*+#;%wE_Mjww!#ZA6w zJa`_3xP8Bc^FnKUhxLAgxiSMha2bI<1W6h>u{v6{8!qY2i3pDy9t(RPj~4ArFzK+! z@ZxIt6f6Kqni0~*5m0J6GuH7Q-?8KL_QM@IVS7oL?ccN&`tbK*Z{I$}JdcTykpxavA03$ z;`I>|Mmdrfd(V|7AtRl9$r|1lp!Cr$PHz?Pn%&p6QOmjxILJTPknvwc_~!QGW1s4LTYOo@j&=&!+Ex(Rt2m=kG8eYU!`ZI!Ao9mBNbLX%S4|D0fdh427g$9gogKYkTIFlFsocQ^eY!0P2z2)=LDWp;~4-&25i{pcNeY0Z&NkoXwqRc<4*`kj*}l>Z});O zPT&yT25LZyo1TvWi@Um~@70lK_+qKknifT-PF4qbi+C1rq*~p&-X{*YHZ+jGMFQZ` zD3a{3`Q$THWC#?ra$X6Y_V8mIz0f*F$-^$L#4*~ z9)E@-k7zFY(MrXwUPcYrd?%Gd*_0Udp6dz9%lN zKIp9di({G-S5$cMiGXOL03Slg63j5%#_~F{)~9_MXl7 z;B!HTJ-RUceIErS)d7zcSDDgYqKwy4+yVKf+iJ=KD=(fD(xbT&ww&`%`^@Bs7Z+`B(=yAqEQ>>HwYPTT}27s2s#10SG-G1*UZEW;? z{_98DdkCBTuVcG<8j%jkyn*%WgqmDkEpTFdM&Vd*zGD=p zCb3S;xQrVLIxg@0&N|!hr=8AEd+3}22)}wCa$kT>;d#(TMv#Z)^23->j?HZeL{z6*8lO}NtGf4F<(<6l8JSb5ag{@7 zaTSc8B+@(yZA+UcZZsUFXUwd;E4te{!JU@8@50wjr}pH!X54ERw|E={>{m^^xCl76 z(Bo`GMtJa@ksCUv0_gRm?pk9`>y;cm7(0XFbP-zwj86r3o#-u+nm67jnzmTTybH&a z4YtZ>lLXS2JQfVeCRNPS^6>c`n@uWx@Svxq-v7DI9V88D1Y37-g% zr`B5UlXboHUes~Eoa>x=G7TvriS6pBo%?$pOKT1;o59Z6d(`YnuXLd_qGI*cfg&PV z$xlRdO4pdZ=yvq@JZ%FWf=ic!Kj3gR!rEsH&^|CU{wlnwpR!d%jc2Sf`-OW#qUxKc z7eH_uQ=*-&Fw^JsCg!y#x6*Hv^{R_;AwF+Q8A+Cw$80!vP1qi=0mxGz6J3HV>hSdo z$F14C?KfH~C4VL(m7b>4s=j|e>`Q>6Cb$W2PR8DOYaWqaA6n_rdeyvuZ+-juy9dn+ zu=#zWQ6@8^-sb_`{6mm=F7ec^cjL_i@d_i7JJY8p+MdgHAxfC4oYX$e?$q9PzXD%G zdanq2(Vo6h&O0gUhk+sj32yaksRPBw^_ucbs4*1m)Hgr%DCzHS>UH}*XnKqpTd?upDxz7u0*eZeQZW`*8uMy{46>U%qsfdidkGhV;xg7vb`Dz8MiKQ7Gnp zUpZEb2=1g|5Kjoc=*n>Kc>65xk?Ie)&oV>LG#E>L5-r%LqDPbsyA;p1e0rH=RzNAy zS-)ez7pJ|a?8S8Eb`_dn&dApF!W7Q3RG*MCR;}~-VK1~tHw)ovJgPHuyY`H6-l1TP z@j)B<_VOQ-J{s3OpWnHS&U70IF7?Yv+;!S#{JO8D(O&JQ-kCi;u@{s4eNB;)^57x=yb#*=yqm?Y@F;Ay`?3r7 zfZp!esKV3Hdsz!tye5)&C9)o*77TICd-4$B*q??7#Ib(2b?mhyo4Aa75OHVzimtg# z@mYL4)nNJ_hc-j+oLWEcIJUY-Rh^1^IK_F{K$`dJ>DBkxGjp#ajvd>T{@~h{Z67X> z-JlxNIfBF4@1~F4jkfUWplaO7lPy7UYvA3JkoU~GI#aC?$F4N6LiT#Y{KD>r7a2Cv zxJTMu13F20sQ~vnA_W_6=RFe9g-XE26_1Nt{<@vBm;2{>8*j1Qwdh0o?0UjXCi%*e z`=W5eiTipLcnq;C22waUMK4@C(Wx2reE--d8ZF^q)&MEl;!Zx|>~lmu+i9qrfMoTD z*7yL)r^kXrp7w3^m9uMP8p_@{yq#szHiC_;dFH^2aEVgtAHSav^UzKE&_aWqHlmmBFhuR6aP zcg@vY&KaJ6aOcZGEJF+#H87!xGrqBDUCgtHE}G`gPp`f>Iq~jterL+SRfSrEyMAfn z=R^o9=GLNZyPoL*`n=aKG6h)Uy>jW=Gd*Wj44WgXPf-4Ux zi*t{2;I*7SA}l`dC7P2dZadA8q-TreJCDWjI-Gr=^`*ORh!&u!w4poqnad?*p6%V& zZYI)nr=)uhz&4O(v*Ru@A1=iooRtf?P;e(uK`&k2k-6G*aPBMD?Re?1IxK-`JXDW$ z+dYjPcMs$}Iy0Ckz3Jc`st}*i{GpB^&Az&K96%mIR6JPXt?)InuXcK(>>#sQ3R zD4ayJn>_T-Y?{4GCzZKnX2zrk|AgB4aFwR^LCNC+F^&J4j{;QKQheP|CyrLq2e!Vu z9KJO(BGkCU@sZ2B!RMDW%cJh60aPmr8wfE=j6tXO`E6;MA%)#3BTRkAxz4|%YtG1i zM=i?vrZTW^SzF8H2ojFz!ulR}9MLUo8j4+LU}?IbPj{k`b@Kcht130ZQy_okJbU$k zqXZ$_6?N6=I{EfV&ew`!iifXm<4f`_)?m=VjOPdPjEoHWI?SL0z68m1wIWv%5y zdZ|5{u0|fXZX(KOf6)UDyBd)z@>rQdkxej&_LhWjrglId?W@=@o@Wv!`|oT|_=?*>n}QOekPY^>wMm+g>xtn2Na{Zx(T}E&RVW* zZ5{h1tvR%S|-X5O~k&k{WI2!R_UOw%Z$1lAv!yT1(spkb{~mkm6%=M*}_I zpV>dpm`7qAAA+hS4r@AQTYF7LXU??TZzZ^rIGfAz&_h-{0X&qdc0Yw*l}4$de~h{?N9JZQe=}GqQ?p`Oi{B zwmG$0z6jZOBi%yyXjyT?DZd&v8|2~eY+v8R$J?YPf_DKW2=Y^qy?>oCx$6V%cA_cW zSn-mP%D5-d+uosB-^rg>QboBB;6(sY5h`%|6%Gm^B?0V^$@$yQk_PW0zSr8pA|`+N zMR}j$%eVTpe7UWGDHt~CY8u5}TGA2p(q;EG7 zcr?E5)u05$ad7!LTe3t=jPh+01DI2j#8CFUA5J5acNcJ6pWAuZ79>DYsc z>vST-rU<1nUZ;V1*2Af#B+ebtp4flyOHJJ=YT75=HWof!eE3CsXWbHB=8IgX-;AdAFL%mo-(;) z9Pu>N!en1V2<82vb4+jY9gQ1ZLr>s!i34?`omvtD&eUIU4mUNKw)Hl)>J9jecTDG_ zbG8bko>ODI30#NlNystLYihRO7kyktj91d6-t^ym&94QBLGIYVLCB#uM@dN}-yP~8P|)Tk z{^kzi6pv=%i_-R(0nh2d*RfR~8I88qrwiQd<~Oxn_txoC4k`;dGqe7FOMmFcfZfS= zx#rN!kimHVKr{ELr=4hX8`3W&>PPeTo}f z#7^qpu~p#|IX2yz;4${jTJfZ5dH8M#^_-PubC<)ShvM$N@*Tw<_$YlHwt%PdS5Fqa zZcz&~ZzAtd23$bfIQkF#CCCwK0E@e2gD?3&s&&Eag^yFwqb*+Ry!gwAU%9i56sc^f zzONV%J{xTy`Ph7uTw#{hfrj|B-4oCG@`gqtH!O@YcGUEonO`TD4M-qE6ceMdxB=Gd zLZ@6ee6pyCmX;W`Bl6r%De9wj8NpL*(H^6PZ^zy&4oi&_yBCrEdi zhH#&BHo2V`Ow3TAOJSP$!0km~e>&*_KpufigVhSQs_Yn|) z0>8>#&&#ko^sqa3^a44DhtxMRR7Bq6xyD3N?O**a-3DJpq*q1Ia|g(m^xQTQBFX$M z6Sok&-f&e+!0DwG|A&!J0B3}uK3(ybHY}L*KY$GZoFXLf%Jn$BAE|RBtKZ&PjN;)l zC>^vY*jp)Mr`qAxEW@&M$!nI3AcsQWPIAOH@&ngiZb4xZJ`oiWH(#a6e`0sjtK!-8 zm&4|A_CWxVpcv%!@uz!IceyYqem$``gRdtxyJY(Ta>S&gp+)ieBUT5ObqDXzvy>Yi zaUTJ&JzRmiM;0vfHBP2&Eia<{P;mX^RG$FAgW%&M@x*QfCXV4wpTqX4473-plGMzy zM<21@)LC`eVS41;@RKSN4L_BuxNc#S4l{Li`}ZbQ=7JGf?q!YlDXeEl88{-N(K$%D zeV{Zb95O(zt7{mUv}L3;$?-PPdfXT{w`(YJ-5v>HXVPP5A%jbvE|y_Fkomf06T8ry zg*11K?nzw1sOHGLZqktN;p^Q14T3xyd`IyNN%~EDjOBRq*|_CxV?Q}wD+!hsD9{Wp z)OER9e+e%J$cjZfpFFRyKP`%DVsF~@)=yXs|oCK}t{u=^2mV8F7dFd136CnUa?uM>_rnZ}$_={$mqGDs2cO?nQO`7^!54udQo!p*uZff193&;H&hDY2r-T@rn z5|u8SIclAau8&M&u z;IlhZ(eqPh*JMz_v1-{8g;KHo00#o?kO)OGs9_R^uvhf4xYG{&92eI0rpMIrzKuJ7 zE%)?DLUC=_IOUi&My{y#{B|TCv=h~`I$Dr&Z$5UD*>mu17gzSoK%=JDwpb?W6I=MD z>h1w42=Wk6oQO8s`}@7f^m1|_PEhYtxiY7r^w`Q*fy4Nkk+r+PVLUCek~Z4A-I(%K zn_n^I&WMIXQq6lbGHsq7q<@3cZOo3+cZ}QuT!7@XC;0B+s*El3apffY9ScwMkU!>2 zZHZR{l$#E9Rc#D6x%Fxz7WrmE8#3%eKKc+v-YiueDWHz7_l_pk$BKyIZ~Jfr%teMh zi#ld-?AiMuM@w^`!F$rMw#(SEG=reEy*GWrcJZR3tA?Z+hST#C^VTVA`E{wm! zJUVt>WMItp60R$n!izg-b|B;4f;=&;(Ln_lkx4C$hVAt;_&eu%#6xi(3J*m*l*pcc z@N7;Xu&7}2%c$Ywx*3#L$jvr}5DkMy99;StZcojYB8N6omgG;B54t{52Q$Bvdgz7S za4(5t-Z>VpI*jg+dapYr=`x-YGuY83Jxg9!ChCV z)ok}q;p(d1j3>*#Aa*KpTZxZ;a%0^rzhYJY%vW5XntH44)SZwEBXU;J54plcEnVGs zkMFFkBSw7Odd@!t)VJmm2OabELZg#C;34sqLdPjM#{(Ilb?^qH}-gMGkGz zs$}Mr<1wlC%3fSHujr3MVDTg5G$Z8E&MH<^qzye=vt*$S9OGawK&oMZt9WRC-%&kuY-ki!NuZ}TG54%;?EK0ZNZB?nUQzz;c30J?DT8b9f zUqi8NEG%r4%(08K!$ zzm?7UhV4r5RZctuAj^>M)GD&?0dK17X1U^^1ZJfRLN!Njo+W;iqOQ%Z)IR(E8sJMH zCk+=>fMof>t!X<|hHe@SI4gTZPFzW3rJiC@?0DP9F6L^Px}1XOty-fkb@z$YO~0GQ zs#mC*E{WI7=a&xW`IJ1dej!z*lnlrqlP5GlofC_5IxU&<;c|+KVL8`S!$S>r7qLo= z$L0G>k*2ASW>2@oVR3N&bM6KL6~m+I?EBlwX48b|Fe>?a4a7$Gm$C%jPr^Edr)>b-9i>vmtEtGh}) zSaYXzsE+tbh*SAAva!Bl-1zbDDXq>LB74%4M8j-ey73z#TjC<|KI*p{LN;2y@AOZd zq#m9EV!rK}C)SVDUm4k7=gm2Olk?TQ7J2lfh7I+5+LxzqhzZLP|Fw$7Z3eH>+Py;- zXt%mOOC*k*FbnYL-yIt)Ox!_omh;QI^bP=r_!a`f;`}!7l#IyE&G|QfjZg+Yme&-l z+npC{*85N+;sX6(>=5Ch;=ll})7x|69Nw}`RdHyipKf$bdHtIC#+wfF2K~SZ;-x?l zI8U(dY?~G1LOe)63H7Yq&`&|gsZl^*AaX!9U_(fHbrH?67<^oOv96MGm}oB9L6 zKsa!c3VJ6Fs%R(xdAv8o(f!%68v*lC+Z#5B#)~)X+z``9wuLf|Tjqgt7jhdGH$Z$f z&nOgo9CcH~iS zOE>(ewwHsO+I$Op#sS0Z#F~??9&bDxe<*XYAt6a74z(vG0gfS4Cys$izzJN7wJfdw zh!>YOHS?=V25(a@9Ux$`SAUepG+p@M9fOTHxYz?OQQNM8$#1sugO^f z(FZgRCDWJ9XASBwd42qiZ;OJ->5pXX9>m~=witU!Uq7|8`!i|#s3wuu!Rr7OUGA=H z@y8f9otAfx#D&jW*58>5Ej74Nn0{C&IbcWkD)d{Tw=O>hJbPEulV#4x4! zkd30_C?xy-At$5LoV>|(+rdKJVTzF68sDpFbC;0kcFpVrioUZ^_!XsEmG9gw656-T zm(yL^l4q~vyip;lcgqqhZ%{T#qlvD}xi3g^HtAqUX+Bi*jkJEw zrqDX+-`yrZ+qFCfbXR z>kdyG#1uvZd9lW~AvJyCI924foMqF0BM7_%k`bU;7QkGebBN&5qtc4Q+%oDb(`eV{3OEn9x?HIGpRz8;XQk9N{W?K$JK zzU#(W2U(vO-H>tqk%|c!;#8xuHvaByCGFk7Ucz)p1buOIR`Kbql+Re_bg*dEp&JBysa-}xxVI4AANXY0->^8P{;rCf;5k^WO2BHnZR7y(m4 z@g&HAI46f;{F_!8Ci8tm?XAx|%IpJ&{hzrLtv_Y&bMFL_;07ne7h0DMlk-t{&&e%N z`Zru{7?40n|1N`EbT7-BrF!;VKR|`EFX!-nG|=$T>+#kat2w`A&VUjEI}T={#m;HoNzS>L++N+q~v; zZh7l=f&307{0pY?LRtIHhS~tL-ZiO>Xel$_a51IY2Szr+GjCgNAz#|>Pb4++0(ya@ z#6{V0osDs}-~AyM|BlP59SK`7p??ECF=v^x(Ztsv`UQyZ=Mf5 z%B3^8rOWWslx4O1EpgOqo@2@@`M#$n^1PkO%BqqvwOls>^8B)pe;LA)M0w) zt0iy%A;}+*_0X}nC%#(hIfaH@|DlM2j_yzuO<;WZh6zdjKD+V7Y~N%Om@YX$3m^Zq z8`1w38x1Z4?Z1}WziGKS!#OMfr|+`(lMdl!FMlm+yO^d^BBq*TqqS@L#9;}${TmM} z*4Bspu-2#aNu#|(yiR6Bm*y&+3arGc>5GdVQpg_PFnsL=$9)kSe}h_p3&1!{U_5bf z;RP(N^XiBDRKn*kK8WQC4yV2nv**Fh^A~Cky>s6hk@0mT>M0i2Fu_$f`jWoc#8ZW$ z1UM5bd7KBa?o@SJsus(ZknAK8LW@fhX#axAhXn)y^3zywzm|;R**6s*blkhSO0%X* zFm3EpmuO(9={8=YtRqJHcv6xK(&$G-P08a}(S_4?yC1FRiW?k}t4*Qg;(mT*P{5kf z`Lx;zz%`z9BISRldrBjKXyQJ+M@j-FXX0Nh@^pghj00>&=&cV>YNo+;Unt|+GyGKV zDoWQ^++~Vgv)9(6;3QI_)r1$no=9&!B+~cScN`Zo%s932##G8ncl%E!4b3m6sY%X% zy4mnHSOe(;+(0HLLR+R%RP5!nn1?Qt3`c!^onmX*j?b&HbiPTv_R#e3elep84Lk`s zCkc7noyP77 zm$WyYkt*H2PQ5o;S}TC#e)0S{o<&!J0bH>bK#zGr@<|T}LP9-{Xkd!kLA;;WKYCb~ z&38c|dQfFAt|KcZ$pdn$VP)_X*N#HOI{;4(^^iesL__fKfiB z!5YOMdHUJi6RuhEfVm)BwBs2$+u;4_{1 zKg-|~{PASdv$LZ&Nv>z_uBVkawFT>aKj5uUt|* zwqdXA?e^>_VY|n)rNOPC^~>=DXUlYRa)xAM>a37`dbenlI=02>hg}`id2GDx<=AcO z`R3Vb)VQ(Ge?wP$^F>dKX*)!*<9LiN64Gz?-iP>kYW zknDoVo!*JpIrwJTvo!-B*6V(jR8I+ee<}PN&uE$@(9O+1p$T#n&ORe~Hke-+z~7gy z1a`K&v|Ob3#00#-;D=alb6FmK2XP8q<|`I!?G}78dPApmZdU&*j``XPmxhCsZq;D& zE1iyic?mM@-j@xk6A~alfuEV>gmreGz}X}0(-;7p?t_OMhK-r)oaWDNvEwV67NbpI znf0u>t!tQ-WXD)X{s1_*qSne*caViAG>B!JV0u4%dG^H3mLcD|@S4CTlv1xpan)aR z;lafGfPLR(aWAH5pNmS(ohi9R%p%%5cMjNh^x4rjC$0!rKYLct8fozG<`m%}6iltv zVixz1{zUWPc>bdY8ub;`Lkg73taV4*Z+zexU>SW88W{mRU-96Haq@gJ@GN~jxIte0 zY^BX5#PAOS3ziW0G3o-YfldT@3Y6K#<#Fw`K=Q{M7MeC^17lUy%tn2R$b!NQimL+*fnLQ5P`omwMmyOG z$~h@U44b}e=q&j%pxQIlsI82jXW#n3_FUR|4qp+V5}CrWJwWPfQIm(hB&G-s%uQxpTrbdj zuq(b{K?ks+PC@8l&;WqNk->ENL2^%MT*F6l#~6}0Ph2CPUmwu+D$lx7<_1%jFv@VB z_=gkOoRAboE8M?NHjpIu^?uT^o6Rmq=s#uDAFC?i=}qA}orq1N1*`yM*n}pOHz5X- z220?043qvBS=QiIoEqkY(;qa z`f7U{mLT`~R})S08rjj^mU(_yV1D{G04HB@aGn^DToHYV)9d;?Y7buhpdxUc@_gGv z&S-3eSp*(AVc8>5V~54TO%U!(L8uC{oUJeaaj9-O< zMocnp+Pz^kL*0NySi)aok2x9=D=^|7c)TK36sz7f?PvQ^8vLYbhKB2w+@twk&Ty6b zJ9-y$#%Atc{)=+9FOMm$ZB{+Uu9zoo-Bjft_%xI>}!E-(%!&Uh}6#~KWAAC_+6tUT03qRF0VrYA&8`DJ+%36sVU{wqHGTUZ z)Qxg;To@@KZaCVH!-tV%ghhKhI;KD9?p{x#lrD57*d&`i;GW0@x-QnDfzMGBGugen zfh(**WD^R1+GA%sTO7kS+)tUN&n^SePFL;Ta*>Mkf2i8VY`)t&Nm{betXkXP3TkJF z_N@9=l&F+jWWjQ-2~y!3gP*JSQQv!WF@#%twp_smZ1` zEw8=4woUrk>2bE@mo;A)UUQ-6X9)Q6wZ8}8Ms6)jnO61K-F6r7bP~ksVooPC>@D)PWV1e~nOZ3QLC<8-@03ggW1Itb33(Ks0ealo za84z@9>21dqEC)Ef%m~56u5U_ri(k`XRg@ddnxO&xS0pfy|a%RTz(?`4k=77XndX8 z0ne$x`@A>!v$`9Zd@R~wVhr~oSR?Z4=Bsnfy0{yNSB+nEubH~2A>X}nb~$pFBJ3g= zuAb!Z(4FG)5Q(d_U-I|^cvQYz3V7$8f9HK!`jGFF2sYfX(o>a+^&?s{p9F8>OL}V5 zu=38b6`Bf}G)e;MF>2#joL?f)_Tu^dWXFoFu7{~rtci?vt>+(8+f!+Njvee$|~grJeYB(ngLd^OM>FGjPe zPf=#?EB>r5o~VHC!)LZJskH2F4bnW2ShIWPa0UJ*IqOYw$T?QKdE)~6=-sIZtGfol zOp%B3$$Rt9G_|q5KQ-u9M6&>F1NCScV~T*SM`|hb%}ukd>6*FrNbi$rus^kwW@7`L1Ds~rR!Zl+i0A-NZ!|8mAZw&5A9(pc%XsBDkl*f%VwLgKR#=|?~Sb1Q_ z0Di?}xZu5sA(fG(f4^y|oVG3C!V6de!qM9 zY_ipc>lK{_Ru`J|s#$TuF!fX5mN8}M_OADy)B$3jxJg_~q=RbcE?0?widoyvoWcZC zK|NeIOO|eeV!Thef>_IkvVA+Mi^gwUS)h(;D)&5k{Wz~XE?Km1n(Hj7X+!w12;T|) zN1HNkW=fcyx3D-dFc9Zw6hm-nz!hf!Ox)QM1TTc_Wc+Ywvfh#4D@j(F_l!TDs-eHX zo2TKKvl@l2RxQV0%=h&sof1~r=X6vW<=uDr;CSMstd`%b;dHoWSnb$`KGW@hF39DC z0Ed*2T>HUeFMQ9^Trs$FtDXi^Dfvj)3`Tgg^6fF69?CWhcMy3B%)!#wRP-;HSxZxyL4;pXD-T( zG=0L{BKI_~^}5gm1S1egD3ej@i*diAI-XhG?QmS2v>ElgO9M}Kmb=GhQTS}`AB({= z0*Z{$a2X;%HUdcIV2sA%s??9Rvm#DvnLTjc_oXm$O6Su?55q8?j4qQG=%_8*6R_M2 zSR9;kwAA;|0A@P_nnC>^#0i&sh^5{?p$QotX~Z@c%9sZ2h?U%qV7+LLSC!-S@1DFL zaHMZN(HXk0A<#y1f1`PHe-M+k^JHxUV+D5C6mB}w@5mQ!{YP3i6Xzs=od6+STbZTO ziH%`jaAr#Rbes~vqZcT*(Pf~5^^(h#s2<`n{Bc0>cr;w@FR%w7)K3lt>%&CWI4B{5 zt|q;6TScL5`bSh8vQe=1}1n3(!UHq`VmgZUEfSP6TIO0hX>P@D1cj={wBs zFoi{ksSfWg^5i|o!g8yWjB;Shn@?6VkGFyoFUuJ16r8l3&0Lr`sfJ-QZ&Z>s;4+TU zCcFMsJm*+O>Ak8cPavP0A-p$0h8z%RWt7Yv-OJ*9e`nyO=4bsiH;CkC4|2$1roY}; z*@~WKjR>!|o>txA$$N-1@R@x{`nl~&YP;IQ3m0zmHx>Z%OMPd>gRF14%0!SBogU{N z=D+BqnJC9zJ%rMyzaGLa`!TEn?~N?-hV0>xn|;`6ZPslO&MAIPt*Om2NpT|crO{s38muh*7dWM+T1s{%XJ|z-L-qiX$rR)kZJ`WJh zgTlO_M(pgoo(n8lEY2qxHJi;-SvcrNztHJl$6y4AQt_7F5VFX3LeG*pZ$ED@B!?G`=|c?wyUdQ0n7~h}88F$k&Y& zxA+ChfLlP4`uzYAtvlya9|-o3NlkB_rRpmt(X1L#Uf-;u&Ni83Q+ynhUW)wDa5>We zEu?clCG#1qEU2$Y3r9WDd#l~1>$R{sO>6^W-+SpyrbEZKuatW^!PF!GIRr(7m`>g( z$Nc7?5m`*WtXrt~Ci6+J?A@LVI^!PnvTqhU2Ek-F0r!zf9J~RdPMh z`fM(@h-5V2{ADuYjnXvg8bl8lZ2@PP#1$ZVIh-$km`c%a`epnUnl`THhhN_Nv1B>z zxKJ{x^EJ1W=6UK$5H})z8|$#^)#N8^(wj1lPN(8lN7RdEB}@jx$FY~13?v3 zzCtz>;Y5}|%H+(-!$HliAIaw|a=DsPk&QnTD5PJenn4lD{uHKaONnHgakrIz6gLBd zxq18a=YxeN(t&&xmw}Un@#*3A!Q@PwRmI|9>xj9jAi z=cjlx%J|*ZQ@67HHN_gS)agh<&%LPg+sa!`-QALMBK^pa%~@Oj0lGc!vA%PLR?ZZh zxHs~EJMuI~Nq~gq)JSvW;p&Auy_y{Nr1zm;l@jfdAJfP@BXM=udl+8=h?YQZYPkMm zKul46{h!uuG9_q`Gu{U+>hV`p46mpNit^yHqMRwzHPc5p{^BTqQO#HGt@a|SwA5)t zdrNPb*=I5szu7?C&RfvNAm#{MTz0 zWS>0x7gJcHnflAai0?4A)DOpHyGExeC6O^43T8HTzZ8qpURUi2JVHPm1}=a>>N~g7 zG+wd#sv7B;UfQ~S;zr%$3kCk8r#jDQc^y6rxjd-}wmOU$1wKRS0)Mc=F}8Z67s^?zB+Iy1a-DT-l$$`aJ zJIn7qka7n`kx4*u0Lt-h+gBpAv8r|w@76|8-E{aw!i{-w2Ex#gwU z9^JqT8lH?KK0d4!cA^(JAtWTdXWg?z3NA0f-&)$)gof^J(6r zD&0aazO+b0%BIp)Pbc#ld~O2LkjWgi0V0QV!uQ2-&FFcR6!1wt=OB%#s7dyc2kaU{&(401=m`yAqvDxSuPE-fMKl$lIsmy6gpY({ID0Lrw3(PQ?}|Mr^y<`Q z2zKVanKIUlxWS4C@Q_9z9bDoykCe#C&EI=vR{P2g7d6v6=ef>Q?A+o*|E4zk=7$RW zL6Z1`5F@}f`T%T^DXQlKWXvlV-BPy3jcQlwog23^)l9!h7O~m1cJuMw7)QH?MJDxz z>xc=^=`3oj%62GKjYPQgS0DsrOd}1#K{i)U zMv1|x?tg8z)i#QJ0r|dj;##ry1#HGwBGvFWs8AkHS6A;7V;5y2J%MUIr4L$-J9?Fh3 zIN`D()SF0L`UA)MNn$siP(E|qE-~(5A9D69eLY=8allvPX<0Uq{o&g2V}Z~K4JG2{#w$b**zWZ&LMK5~%TZs(-)eFOYf zbNhH6E511@PHl;oFP-8@fOP6q#0lUH76;orj~jXqMVLxmEG}0!{Zqfn*vliwZ=QRB z)q8ky-i^qBH9R}+_>4SqkHtk?OoSinIs}&ELA2A!EtC|wYDP*Z0pU2quI9;+klHUf z_j)Q0US-*qmqNY;=%KEKHis8YuP!|~LEbmg_`ot6F@U;q@{^TRHsyQsPy2g1GV!NL zPMn5zRG0ua(6wYZ$y(5P3rk2@Nz9!4=)r%wSfw$7&Rpdr>puOSv!6dERp6VDrA^V! za84tD6`9;<9&p$*N845_Z0sK54tdEazeiyNwye&|dSTsg(zvp#_Hz2KL5l4Gvn~ZX zG1PgRg(!{KX(!gRS%Z$j@iRHHj|Ay1a{-sAQ>nm>1{ZpfO8pQ31mj@r%BVx&OD7Y- zBmx5J< zWz}J+inq=@cGH0M%Of0IJqr#6(}EU@gA2bC1_GzC;^0zHpzYvX#?xabzrNg<`s{-P z``dV->`PKg%~=&g9T-)6Br)uyy%(_YRAnVuAA#^A~}usFCDdbnFu2R#GpDSHOXJE{UNj(&`DE4uaK zW3s=??J}iPVUc|}Qn(|oq9-tDn3MvXJxn~9;9Q0CBLYnb1oxJSGRHGYbLph5rz>jD zjwKlAy56ghytkfia_Z=)TGBwKQepjHOwEVu*(AOaTbIXAOUZJWzLo6nqinVInc*-h zDGx`Vk+6wpR}Si9snEbLb^CFKt1JQzb8K5m)p@kF>OilD@6}KX6S;2L%%*}^U)A@O zXNNTMympGPj}iPySeOVpP(cmZOXBibM}jZCdOT33&3Iww#Ou487WRF;=BcExPj5Xg zq<_(pGY~q&oOD(&WzS|+vBN}ey_fgc0e*h=%pF%^Y!O3sbATYoo{(D|i-S9l0gELE z%^w+z&gNVLOsR|P0myt^!g zZqx$xk&Xp7d))=H8|KZw;4Sejas}K}^AYcrD+r}WSbcV?UV&@PC-wcyj=Pv;W1SCj zh|DH*M&51DG_*}>0aTch14ORMR>_rQDD9N%-}8QcXGeU7=!LA}r*rE!)2Ng7i*oag z(~-o}aqwYb3NL{$j%}~~1Edl=Qs}OidkYF=G~arfJZpa}B+U2h!#J8MgO8E;Eg+-N zk;KqpVOl5x0pQ4#wvassbel5v`#F?zyB$hQ?DsX_?}O@?`O-H4B+sunLQWleDjjma zDQuHCeqX1#X%dad1}#bUy~EP+q*n#ws8a!9rj!8X$sD6HSADu5o~`WTUuY%Kq@gK0 zJCZ$~`cBZ(U+Gx!p2p5?Xn%%%V4cW9dy_tJNA+i~jl8}|suXh>qLGS^J^;zUqMZ1{ z@S6s%o$lto`&T3yxU@At098|lrW33fDb+|iSzpo`QK4swP~^%R<^Tv_gH8uzbf0e7 zeD{jh)&q^2FXnF^*fqMT@M}Y&cK5~_Glox_`y7R!t@D<}OWvy)m?;;ywn~neKr;cR~ygpiXs~BJR*P(;M)YQWd#ePtcxCRD7IS%PZ;u~ zyvgIS&N{IEmvc?__?!nOQEiw1w&AU`cBQR4@pl9Qm_FSy+{QWoK9TyN3}J;rmJ3{F z9AF3KQ_@_d4u;DT*1J~^&Q>anTDhnN)-Jn-XH56?=x|H>)20+Zn>Y5HQ-wMk|6+a|jIjc!eBVj{;@5j~U-MgqDWB=M ztMk>Id^vWQY{Kd-qL4FAFtYk1%Hy0HnT6lbd_n`-U^f*C$Zx$(3bJ zVvbfHVzAV^e!BO17V#^WeLoIr=mNoy372mM)T+wkmfLq1z9*hI`(Z!6BmT^j{^9_+ zmwg^2;;2v^&nE}+>)s>nv4VGl;R;X|HJcgg1A+F1y74x=+>-5N%-h;T&s@S=w9fWS5xm%*QeW#`s=9E2WcpfyyJ)G&4Gx zP*Ncd*+`XLQY>EJU48NemXzW+r9gL8i3A9}Uv_X--2 zNX71xPl$Nd(LqLJvW3+o;qHzB^1S~R4F0RFUf@a@fW0g0UdHNt=*OWW7e2jEOeA?} zWW*y%6VOu^6`VyOI!Ku&_2Uv7A101=I)jpe87Nb_+S=F3*Bd5kXqe!X0n92U5b|8vX;6gcHtCGA79` zmLYbxGCP;uS>$iYh_!fTHDHcq_e?o$&9>6ZKgEe z$C5;s(jB@>`|)Mgt?gw*xvotc_K06A_3Z>kmV)cFFz0xx($GV_(%?>PS}d=5c1lhm z&VNHk6c62qr1=^3;jTP`eYj)Ag`8W|$-YaM3VvSKKEKx-VM? zTi(RClfKGN=x^69e6DoRD1AbKu2S#~w>b+I_xW=EvtlzI{Vl`do8>zbdPqpNvr-?+ zm^Yb?Kf2-c@HH&%EVP9=nUGKO1GtJag3K4MCd>+wV+8F!^6lo$-k3(MiNbUt{AQIq zU(@5@svdE0=Y!#lV9M)p`Y?SWaB$%vf(ite9s!trYb?JrtmDY1T|)=6zK9|&S*+`o zo@y4T(X@Vr`{WeNRsMSwsOb$Q;b7TtAIQvS~!EPD#ZHvBgamW8Wg0!o+lY~1UZ3BACVRyb;n@^!Q&$RWh|kz}kj$j9}X(o@xIgi zoP%|b4)P??ne;*Va|=MtKRfr2o*1;9X<&|uUMxObyGJ*`4IG+CBrv=Z{s`mQA#dZL z!U#TH+%s2_1am(%PLB;c+0MkA8Qb(1y{j;4Hc+z^ev{$E4oqJhO$1s7wu+taQIx}M zH$1J7IBSx+jb=-^2b9r5P4IER9cv2gff~{TE9iF4N4U6NMjn4i`*EbrnkDM37t^&f zX%DXtr}dmOTqVc^HWxX?Wedm0MU2Lh&bcx?N%KuPie%G#dIsetT|5c3}uDu^{ zW+i?gL-b^fmG`pdn@4y9iN-|Xr!|P%yc{jUhsOoaQobQuX;uF}UUiR%V5kecUoI-q z!wqjfMO2t@q{#h&e9+r-uvuAjZaBl%`C3oj)I;NZ@?hfd>yQCo3v$xyhv zvWZ%E2BYOS>s=C1wcExkQS;|V{yhL((DSm=;}l1ph+pHU;7b&p@DMYGN9 zi&c9(fymz5?W*J$u64TbBM<=7niX$IQe{XIO)}La)T*4iP_2JqK=Cy(O+muY4hj8N zg#}7|!27_IW^k>8Pk#UZIYUAhm3Qx5nX^+pvU)4U9zA}$o32qzPeFk8F)_NOQM1;a z7BB#Ap6K5epop0eWKd5xFHq`ct~s(HIHJ#ktx?b7O%gv29c{M`zir**Hc05g9XSnX z61spX$x8c-ze_lMz-B*B2q2z&b%M<}fHP+Sh>UjFa>s2Yof)Qw1z^0K%#M$2vOO4D z-N)vPh$pHPdW0|F84LFWb{o`xRz1~Hf!{~QxsNQ`2`1ACI0U&=<&BK@MzI(ssFg}Q zlhd~jtUyiKjR#}+?o(1aiFPc89@rp-4id0#l4K;n4c6CW6RrPu)V5GYs)@vZ^FTed zfVj(BJD)OzpY=dHUiz@@m5ch8l1e#j`5CjuIX6k*JhTRwv#Ej~bkDW4XkcI zMc6{t=HV*6pXOa!j}$IDA2*0?$qC3YCQzz;&tz)HM@HKItJxf?*vb+>1vC z_`%f5EcJuEZr%H#dWw91AUS2sL&MQ8y9>s(JNaHI#+CbTx2gYh}UfjQAmaCxeLxF91`-tyEz`LM*! z*Bf7)84```A$$2QBmB(c2lwtZz`NwwRWuyb?R7{gbEyYnN*(oZ+Mb z;EYV+-X8Gb)7{-}*j>h64D}QA^=J*}JAQT{9Y-H+Gw%9QcSmdKTy3}_HQ*HCG)0t` z;h{opGI?+8gyH?zeIiHrtw_&Fg~=yGQ)zj7jID$iVY;gVQQ$s+TlCk%oiDJIi%r5< z=AgQdA}jZHT^RQX`XXzl!QIc}T+UzH6hd34(#;5PL;0oGiQrUVpa2;<9S$I%h81w9 zJ794%wAqvF)4NX9T&n3F^D}l>*cds*&tQ>ppe*kB%cG`|SlmLIbW0FlrA~ptxvdwy zh8GUAuRm(5cW5E@#;Feum_$$937DKr+`LO$>%#lDJ6_hjIWZ+Kw7+KFJDEqzurB#L zF)Kx+aRe5p0n@x1i@OFRka3DI$E09!a0!b9Kb-+wxt->+35y60$Yj(p(CRPZAhvvx_isjp^ix&yI8S~Y_qFI&N?4`nc}IN;$L-E ztlzmFBvjIKqyVkiuU$NgU!W<%yKCh~M!ap}j>zmB>)-#3_O=hO2~hWn{^W@hf;rF= zIYJIq({aEYa*Z1kJ8*#Vs&T)^E={5j!Ba^h_r>;8Q0Vqb4jomamm? z`f;VQtH5=>D-*5%TTEpJgZPl3>l-GFE_hMDW#V_L*XC5N4YT%JiS=E z>s{{gtSMoQ4zZgw1m73TQ7eEn0wWJ8H^+Ko_vZCvqts7y$H|**G*A?;t2s~~*T&OFjKXLhssb`10v-$8JhMXUVXWHWyXUKO*X%Ji(-!pgY&mLVcRbj75j*@bG62 z_IafW{0Y*>C!(FJeETEf6xTOc^)tB{Ygon{)vT(faOH5u=~oFvBuN6i2=ZhoX|U&! zWL*dgip=Vh2tL=G@!q=QIK_-bJL@MJTPbTW;f*zT>*U#O7&vQpnq?|b>G%SwQPjhyQTMTS{^b1e_fpj!x3!EuQ+PCSRI+FO#o|`Dwq$_Aw``p` znqnTTOhhbDEa-%6Hsi;Gj~mR`H#PkdtLt^~Pe6ZhVTzc;94lIF{F>&{Z+ z)JN|m%IrV-f=Xt-^tpEu!uiF3R?<-gaV@~@f7kg?#xTvA{~Or&H}yDgIOzs>A{v>< zK6zr1z(gVru8SAQ)NpMGz(+Q|_}HXz=6Hm?FHVfATARIRGd}oS&|!}*On=`;K}mHi z!S?ZnIYtKX2RFEEOLML%8YdbuD<4w;2r?D_?w*X2Y3mg+T zBH;YR>)F?;GH>cjG6<^jd>zcRyi|Xxr6gsxg+FNHLIcuw!V`-V3bU8rmz!v&A@H8l zB{ka4gWJmmZMQe3BthSZw3fIH@`wT;3+o{@UT;>(WFlPxYuufD7qv#1)p$k|4GIB00Mxhg#!g9Rq2Vm z0M3#4_Uf1uHM!*?X8ZR)F}qbdbkK4)D;gQSB%AQ=q&MB8;aZUa>k!L|#=`mx**sm%3v5 z-awhEpnk^AXZ&3|M68((Ej2!X3HJcwOFAg=2E&~_JMN0hvT3W(jo!3S*(6lD&|Kpm zTPrQh+b&&!uLUG)qn+j`DT(B}LmdPP+T6t7+(De;(JXvX+8#6DIX(C~wh9ngEDMq0 zH1vFY^2C zImEtseGd{-sDm|2939XP1&RO>WHJ?$YCsQ~A+KLeos?u?`as`CTug3VQ}tE7gm@uC z+pm-&F)ZlnOD-fIXga{v5I_nGT&6OhL@*uXzFg7LP861AmS_4%J0foJZZFT5;$1BD z${U}VzNa-gL6-*#6tgF5_7*ifAV|3lew>oMJdl8Gy?0 zp5Lu`&X?oX1=a#T?-vCTccb61);9UxyzN==c^h6FkQFC!x*rrpN&@&nr4%~5a$HVz znh|BEyg!u^YVs`I=fv!AEtim2jfE2S$jWK$Pg=D0-8)p#m?PPAM0S15fhXQdX{{(O zT74q&O$(dJfC~UJ%?$d2SB#0r(eP0 zb<`e?Xjy3aF?vbuxJ6RVr%ly8wD0ah47u%fKKD9d99%bi9Ng)%xOAAJF5F$1MU5lQ zS|HMY@#fBgqPWO7mSiNsDAOqbkO*IJh=dIJlyG+%cFg6IdKvZ50kq zhT=Zcujkv5aS2B|W@EW;;f2BVb6G?raz}j4&1_ZKZu1_;ar37a+OpkFQc0tVk5Nuf z;5_+eBYk7gd96&x1yQ|z3&K&*L@@h0AiX@jqL7XVbAAVosiVQ*iAG5AZ2JBeo#(tp zF72c*6lRbON@!#%`YJgFZZl)TRgCOKqc5+J2^(82Ft=YOn@vKxiK?J>G1q&an(TwD zT)q>l9(dbAFjT0YEs zwCijB%(h($nS3x3hZWyE+TP3lem z&DZ=|xEPq0EI1rYX#v4S1QTNf&aNow3VV+Qdm@CLQ+r(v6NY2kY>dXX-PpEmYbT9u zw2hmjv2EM7Z998^`32v5xUO}uPG)8epIcHdqT=#;J?q!jYqVUUY|7+>|EccsFn! ztqT=a7|g0M!zV$ScOMVi__`dHE(>FF9v7h|qrZtQv4FShxbMHr!;i;EZv%f(ghey+ zcdKR#eJXO9e9{;;yT}6!gArF*)P)=x2z8!81Ze?|!~kw0`|W)n=2K!fqvi zlQHAry^sMivO6+*lokFjS@fWC5Cgs2;SF31%6=%NM#~mX(4H(Sp5jq~Ce$GOTy`

    ;~H9aI$6MoOjI@qw&$Zl5O_7-8Uy5Wv| zGMeKdzE8{;OSx^QPUZV%ncN>j*3x;V1nk%JFKK%36Z_bjJOSo6$dGfy%%23c}Si!*wq{ zCb<_tpM~zfEIWwj@mLh$Ii#Xo^^S5oS5Mv_2Q5PD;wRuAj2<$c zc;W}=Z^)bGa?vN&^Z^yW`6I%-Gv$sK^_Dm2IE?)XcMMHD;JfR=_v15~>7U}_oJzS) zn-#qI-Q=Uz)9bJC113_Jjm+sX@AHG>v5Qp;H=c4FnP|nst{*6^XdsU_G5>sPa@;Cr zvyk1SnRO4#9}m7*D57jlLZ2^#JP~4a+Io zxQTp+3%cAz*buBU&aZZ1bFlM4KaBW!PV?^#%2|=c3P0$bOdbw{!*Ghk`bg-p;UTC$ zZmQMty+6UDSnbJGfJFLU$c^O0(J{!Ex{v52ST5pp^k<0My@(?IN_|%?JrV<=JbUN6 zyKKmJxj7r9u|LaCQ;fq23d=fKrfmy*NuRjwWW2S8xO|6gyD5?i4GjYW1VvMMB% z<8V2qF;94m{`{m*j4Z0Yi6Q$}j+^@R1D^Vq;r|L4Y@28l5-y6GR$SuOcB_f?Au$lD zkl=~RUiJ3H!*mHe>+OMEk$;-@lLGN$scZMRi-F|%#`XM$lz3$|=U51hG@~Dqr;uLmyv`4Q9&YhO$FPLjO&A%!EBWyS ze&T1BVNx`T1rvlEcuYqW(1CJf_mH)!!8)`F(vG<;G_v>$1ZzQC8Nb`qzPRZ}o~kqi z6aB%dVZCr9sy@HlWi~`JL)PJxcla>H&X^`t*n1qH_89KSC2E(YnH*X@=<7exyBbdF zd2|<<=}&WXHYV9B6XBY~Ihxat(V0;m(>%j@EfGW@McCM=jH~)t_RiUNm%QtKduk33 zXPakB&h8Tx!6jGYRdy)J{0tFb{Y6>tO*60dZFKyU`L*SAb&bzJa;Nq&~41pzo-ISHU?@TAN{9T4|xCe8tHz4i7p>AQ$I##U24%G z!kBdnq#Ag?(^MOpVEbzQrWZjj%8e^M_I2%b*N6A^r*Vi^Qi2$XH&9XBzXj74We4f_ z6Uv+QZI=vOU=~;SzJaCLK_}y6Ml-EqJawnpPdx0-Vbt8F>;r}H0S=-kA~7^Vg1`5` z0iq)45iP&ZaJIp;zB}xd)o^etNSx7SssHJ4S?4TQhERGU3*R?8L0-!Eb`*}3cg;Al zU3kD?+IiXXD#$CyB7T*iEb4^%w6=Vmd`H0n23T3c0;$a(1cJ18y2Dl1(Hu zoWBg#c-K-{3ocP@G0!R;BRcaB!>9Q!`pB|{L;P}`X9BwyNZyI zXXqmwixJ=z?t(uHaTcET`XWe+a#T~%})>NwFiM8oGp)MS6a6H>a1Hdik?eW310=wx;#+xcWe#eHItbZ8YW$WTH(o zUhuitf5^3(l!`C7&Rl4#Uv1!R4&cdLt-9d;Le1Diof-?%r)|M3$;)869?^H;<9SXy z_v~=jCKhQkbsDqz!E-W}TTJVcv{=G@-zB7fB6EoTYV9^Yfc$EwJ=N`|TLWozNhl*t1 zX6TQ#fxQP6zp0ms>o%7q(IpxwZu2Zap{ZCn&tgeMT(_Uz4?k{{D-k-G615bO0x%|J z7_gs=Gqt14e;#JUu&l(Bsy>5d`uDiX-P+f$%c6xMeLNG6J^!G)+q=^DY$6!S$W>Y&t$R7Xqa1aj``g{I z&4EM9&gS*5=``b%aVD;mJRmLMtWX~0FOrQvEz$7O4Lu)9l@`bm*TJX2P9>L?J;82QV!rD07v6 zQs=uny0m8Z_q8qhnN9o$>vQlbC@raw#?eAps_ObCQyPWas3L?(6cfM7NXIIjJv2lx zd`MdjTi1A~c-#XJ5=C?_T=&(G&mf6rA5?oPSR z|7YdbGpCS1O0x=Q$aLgnfNFS@1kOB7Z(sqzJpMDI8o$dFg86#q-#=*!-p#e3Jdv}Q zpWUdTkfVgX!YFLSyKl+xNNge9?S_TNV#tQzw!hF1M*coL=;P`J5uHe#`S`+Ay)y?( zI7^JMhwYG5TLn9#5!X2*3PPSaFsNKe-OyX?XdO*q20)>cJFWgyn$*NF*aF+~7MUIv zX;!`oIw2QHIDyVR`$i_ag(SooQ)Ja5j4zqhgx(ty`fqQqEJj$|KMWx+bEXIqv;zhp zeU2k|fn20q`zb86GmU;jL;TSS1ym0ae(uRNys^UgAcL^!`1TR}(XQOwy*aauwwle| zEJfBL)3M=@-FayrYOmj86l!15IqNAVw8X_^O&0rym``McW+r4u%Bl!bpkwAK6O7C+ zHU@PKasP<4Zw&5*zbzzz?=NJx0S?t)Nc&9#e}m1?i%J7lreHBVekk@)K5jd$2I94? zwdKKxpRtRJ{cGcE!<*yKml2-ex8=}pd7rFXC&X9dUL{LOzWJSR4+S%R$?yPKlR@$=&ZAJeqz__D@z>;)fwfS!2liG~>63`%?R}d*Mw#e5rhGKSZ zW&zpv99{+G^S+`Zn$i1@#c{jp?`B?eQ%E4yKQZ6@N-}vdAv~>zSvwCk88+81mJx{^ znUg$PTYgYx7KTWBUVw;c@by(3>0c9s*zOa`W5z<*y}o9KLpN(Ymgsc>67Iid2=kTsadIvoBSFJslF8kIu5Uk{@2>+jm%5v- zn8=(-Ffr0n(J@o7v2im}vD2_p(twCOONJnfIgIWK06hGUT2K`TuulPlU}S>MYQm}_ zs^Y@S%F2tbLx%67gU{-c+R(|frYkj}tF9{nRfKv54Uve3 zo{{!~-oq4&I<`Jb&{)`@z4~IRe^EiiBBZ&a(Yn|Z1p0)7QFUQuvc}@kuuiS2L`9&A z!N5dM)4>iZc}M{3@nT__n^jp9t{Kykpem9K{D=+?CPP?Ip53C2C6ry6-Na_J4|#gR zHZ z(Z5kFEDE*76bGTLjgN1RBbYgbq4apa2kjd;2#LhU>OBRIt z>SH1HEw3F9_pWMUhjj-GCx&$WJp_cA$2E4us0ju{^ClxaAxoVO_u&*Hi6!Vt7fr@L zLcFwxpk$Ru5%LA&mtNVtaEii=LjP5WhI)$dWlzpt)Kp)kH` z*u=O-YHOY|f7HdrHDoi?-=W(fIM_)z8R=+g=qcLR5tIzLj1)TfT;@)?uPu5$!RZIO z{TXi*1t*B?;e3YxV`)al zJ83qcS03w?=F^U%>Gj_ErM1N+Otj?)w#B))GPb5PZ5x3WupxoLfm}1Dik1GS9a25l zuYnz%J1zG-Lx@|d7u9m7x;fK2kiC))%$3t+9o#Fo-&@(pz;aHq#R^pQ-?U23778&$ z1ohI63sTfvB3lg~W=67C*z4O)_4}vBSFTDshxWN-=L?XaHldxK6)dxtQKB8(2jpb= z&RIHLP4`4b zO+3dv#Ptrac~3-3OGCre@wiS*e}x3^F7Wi$TMdz07$ny3A%$=UTl1`3O${@UrT;lG zg$mgh`cZaOg=Q@S(uQn^h5HEq++3rClb&&{X_ofuby#5okWOf79z8qv>eP6O_b$JN2vSBpp@HKav#&wj5LpY>D1VAK=um-g#e># zTXd+!=cTH2YCN*KEn1W7Z19IZfsjdlppv%=Iz0Z5Q;njS*q7XjqH8YABG!yzl1Y%%un^Kh44J?xGHCu(=eO@pP=^cHh;7BUpmL-1Lc&h$V! zipPWn2wwa0k*cf*rk8I_u1H+P7FNN z^2&Cgxda+{gYbHusEuPYj!Y>hZRg(5jhNrxPLV*00gUB2OHpq-nR#sDneBk6e8GU( zF1!ABagPDqEaE;SQAz{EoC%VNDW$fYl=isiGYAEFdqzxK>_lPff90jJJ9OIO>Q%k6 zTk%~&o>xFSJPy(m4avi2y9`pl^rj?0LuGUn=wj+)b44_;4n;q`OLGP#>?e`%+}xaL zc^hD0U^$UrcxD~;&JCl*)B#yuUjGAiX_5R|FSuhz@g;1BJFH1HmYtpTO*{ z+G25e`Huvw_-l*X+z?=AU#)2iKus#&U~Da^Mx&QyVmcb;;KE4OOjM_xrzPa$;^Zvu z?&0Fofk|C7l5;2CKQ< z?YTkzX`&Uf*+%5}2UBas80}sk`x)pdAIMn%BuV`bD_YxPJk(kMlJuU|T$`~ykQeV) zZZ8A1(5IP*a62wXMQ4CA|ASXh-$na%NY=xp5*8f4h$ZJJ9T~7*)Wp(?0!gxne7CUb-MS?X1Rza`Mi-YPXm{^i(j!BrF8Nm^(gVDzE?ns<-jk z)$0?6C|SX^goGVTlPs39g;)+0eeDO(Ck<5*)18B$dfB(qq0SSbz;1j&UfAOn!HeN_ zz$vdVN2?t8t$T>N7oPY^9ib~o@2EjpF1LdnjB*&OgYG&6C!@KnA?jStvkssj+|@9m zg#o<>xNA7?_>1sb1hW`hXs)t$cittJHbPAG;P2fEg3*heytGLFkop4-oCLFdB#bCB?xMt7wY>g zdKSM8bOYCk(T=%M$y1JD(iD3l>z(eDxE)j%mGSKtFg--QGSQ63gO#R7RelEZYUmks z`Wm`d=u4!Ngm*Q=nVf#nmZ%8rUrk87Q0XDcK|c{NoM;#JG-#ncZu#SvNU_tu8Pt^- z=(EK1`k%ZG8q<+2Kmresx+H3^Yk=M+VH|U+p2C}rKa+_MmDk>+`16DTZLI>FSThx? zx*;8i7~l)a76TUMg%aj)8JqqFm2isoVmWjOb4U5(TSA7)LT7gwID&j7gR{X-EfN~e z>6-?mow)lbTNpnZhDfB1+Z(=%B>T_eLM3BiWN!&2CYYQeXIwJ`x{V^zlhZ%;Q_Xna z_iHl`@k(^>g6E4*2_|ms_`m41qd`=UyVadh>|j<|li1PH8b1KKszayNIt`r zFazdMdTn$%tdwLX8+At!gR2;Qv~aecV66-2vFbc~c`6)be?-SbRWUvW?jxor<6wj9 zSYt~PLcHD^-gUMCAw?2F_IY6q(LM-$7D9Juwk_d8An#KwH@K)~7ula6h~PmqHprj)hSXZFAZ4lAEVfrK~OP8Ci{^`G)x- ztSML#Wr59ktW@(+m2AqWUjr`%_~~9MFOH(#ZJ-&$8`1*of&3(?U;C|?->C8d4~PO8 zPWAQyF^hF4F?6s`a^2>x#T4y+0{>k=p2O;5&y(CuO!KA)gHcUnjmWl5KPSm5=ev{kw>##$gSiK|;eX`r%YD@&8Jx$}+lw%SvKz_w- zsu&%{VxPWK_U@Jy3AEUR6%;fZ}Foi_yJ{o=K0XR-bO2lgLH9fdOXaf~ZKG;Vzmpna%m@LV0 z?9dIxE&yP0}xol!0)`GK@e;n)iTtl+uEKm1Y;xD z38#jSSOL!3JT8Yht8(lR{ysP_YTf|sIaS68-RK?ZiLlHa@Y}SPox6<&lk_i5BYr^g z-M!#9J7#Ctw_XCnC(MfIos7qBj8~Ut*h;j9KbxjZy9psi?$kl5T2i{|nh*=Dnz)y2 z-D}0;v~WU*JXof47;JNMb>ymb8083F__f<}r^}%@^kOXuc}Oj$qzO~5IqPLVV9;)a z<>(vqIOr=Y0z^X&m0Uq0Gl0ykPr~b>W+l>tM9-~S*HN&x0%XQyjoD8IX06W;nEVJ_ z7>R#Ua2R=;9iqu=qKZ8lE|t_G-H@#Z8+CUc{US{0cDQ1R9%WxImZ6Y!Dr4ep z0I}H#`vmEQv8f9H2$H?h>s`6XQP~mMA2Fk{RngX*zYt;~MQH4_lu_2q(%DD^XAGP2 zh(b787Il0$f3#EgT`%fG>|v{yTjYpknuAhKBN~RbU7FfqgWKUP#O+)+r^S4b8=mm| zo(D-kWut?iNzzGVqQ`*@JiBO&?MWu=ouVtka`HSYLPF&k>_Iz$%tV0Z4cza$wW{P! zkCjJ(jYLjxLiRlXs*I({{=qdIhr@I5v_c(5Xy|2v_vzqv;ZXS-H%2LZiDgwq3o78q zVBKD^-rZO*e?@!w;&UH@B4YX{r_&kkPJCD1%}tGGP-!)IaAg|n<2$!D5o;>-WgV8J z4)&9+YZ1p9dUN|CaGrhzH)v}=Ir`te9QXyhr`fI&yb($~F z&!lF3tY$v#)y5y4NH|3Kj9Bz8da*GpFhKZ|#^uTAr=Q_CQE73I>O5j2!#czzp^+oP zbX9sfFLpoBe$3`hMsJ5rQw^GH^&MNcZ%a-C)W*m@)I^9SjcLC64T?L%bv2S&EC~B? z7}z4M`H+FF3`{|;wJ^Dc>clZUcF{ti^i2xT@F=7 zkdf1T(XT3HzvI^m=cTqZK-&&qo4wN-PG-}h3-$G=Y{%U`!xd2u1~P5F8gzx0WM-B? zt52NoD#GOj;3hPrr)y(36_zkuj7J7Xzh1ktYO=x>iXwc%oXiE01*s}KMu4wbMX~$5 z=7lC{V30v6%eB6jlVQHEp57y}Ip36@U)p)!imV7{j02JM^au9ZeLi>7G+X>Vc7$mX z85~~vnx4k}KzkEo+7)drAeRNyf%kfTKhBPs@z1x{fBB+lyVEvH<>XjKpOPw|nX9lF zU=~^ff$nJTEYJ}5g@O}o;N8vgsmvR|Uky^%07D1r8#ED!!Ow2bKj&WFlJ@0>M3j@K zz99F3Wa2^+fxE6riH0FDK$8({iTC=?COX~K?K}g6s|sL_Fik*JxU#DS7bu<(R^rob z#Z6;@9`TX6)k|bU7YDgG@;9J;Vj1(?VRK{ zn<+U4AjrdGnA;Y4nwuwDn8SWRVu#wB)9GbR;)OTGO5?%#{&P~YiyH8$zuQP4q{52l z9}{S&oO=^;kXqhOLeMz$l?XMMYjmh~54M*neS^ME%}7th`K;Gqpr)(m^K|akIY%y% z1l=GHN@xz>y0Pp$!%0epQCjpc`Z`2JWiqrlB595>I#h1j=l^tt#fpS_tlYvpyuLc@ zK#1SQa}eGGTRkO2>C+Q^i~vnPcI)5j+Fq$|+m+aO?|>kQYCesqC;?X>I!5x(ZD0au zXn1H!w{Hz44kxt+Hw`_t20aNQ6+0sh1FIH0DJ?w_BLz)-{6n~z7D)0|Q32Qt2>;#Y zhYTl*s1ns3ZFc#{Oh?D~dH)uX>;P&9g5st%Q}Zc?2&0F!s~@}#HkRSRnaH9mvGi03 zt_*4U8xlCZdmU@pPfZuUIx&zA^g$3_iY16;xNF}o!|q(9UwH~tPQYaTN@C`~kQr~J zS9>Eedj%Ot)LU0GZesPdn25w;Sq{aJ;Ukv3SfAb&(Z&^|CWfM^BR?vAM-X}Ac?}MF!&xVT76i-=hnxri6&rf>86kVF z^bv<-A5FgozP7rbnRI+CTMbSMva3s4wZxZY^)|H)2;YEf4#il{XJ_Xnw$&XoWsDwJ z0UiFc+qNx%XNUD{soPvC%Bke3Ym8fZbS3Yb4%KOeFKLR9^g#gIgkJ&rLg5y1J?KRAW0>CH5(>}Szh2?cKPSbE>@XM}J3N|sfpl_PoQR-WFK||^zw1I=A+(E6)dydk&2w zZasnMPy>fCl|}G>KYv7vdI9bcx@}}zI(!2iP@5qx{-G=hM;>XcIem|g_HXtEoP|7f z*1S-y$m1QaG5+XIIvu879Iw8UGrKq>>~Ru>cq)|7GCakj=_kX}hdbsHynGJ2-SITB3{r`Oy;eURQ-wY3G(S#n z2YF_jksrM}X)|U+WcyI!sHngPTT^Fy;7bv=pd`&L@)=qOajbw56DE>Y#Ib*vMpl`= z8rnM&XX5G<>dt`e?_#%ltB+*?1YLed$2o}6!p-_GSLiEmYq>7WDAsXLc;%t_SXu?j zfSm)a)Yn@L_&~wI?PK@qZ)mC?IH=@Uv4D(|X4>mOo!?)-AwMr_N)+5is%Q;2p9)sm`;~B{)+Su}z&C##X?kwu z4F;4KJ;{aw4k(i1CLaqlmawtVPN%eExaTe-=I*BLd~N!&a#|)ya9lf0EX>zUy0`f8 zUC4vzae)uFM6KI)JZ4*k=i0q|qtD?OH%1Vnase$JNDWI|MLy8MO8CW>{7zVs46B=J zW4!vP5H^kc)#;o2Ag9~Jp*XGP_|vQ71wHz#@R*nK2iayY+Qx@sy+OK}Ft_*XUj~%H z>#w_E1~vtep+dN%;A5)hBOpGx;N+{}WYr3&#{4-12KV9D3(5v>)-{~r zW_-y|J{x01V22oHa9HXSW}Qp;^Sl<|63FHNuu;03)P6T;$CSkXfv=6D?p*^J7af~n~MJ5h*L(QH~1dGaew&-rIyVs#^xy?WkAMi)6`l1&H zy-bT}2Gd*5(6ww)7;@SzTmZKS^C`;K3F^+z|9Rt21U&4|%6Yt<N&8>hyCInF z`fv2#$6_AE2t6?S5R5dFiPbW3nCAtaD3g4Rn3F#H%DcJo@>%>|16rdj2_UX{4OIVL z3bb_U&v^Qo$znXj$=F4$=k?OAZp?~IKU+ObvmYgC4@czLM)m)WUtKaxnf=Ai`26k{ zLPlVhp5UhD%RsmyNwM)a)Qf@u+4Rp>^)KdqAOx4Ud^-c~)Gz zn$kJ;J3}|Jknj$1{cG!#)pea?<O#_>AF*wAOQe0B8rR)Bak&0PIT&B~F=vmupS(PE)4Hmc{hQ*1B>)Iroz^*-Jnd<9 z&X()Nae7Ov9OJu1)N-C937v{Ez)6c-+`+;=dqNpD7Tccb7_KKwVis3=82FA|1zHRy1bXj*yHlQCHHRC7Es0=OQ^1tvo(kqoH@l zd8|Cz-eGc`D&R}g@>^M74XtPYKv->01IWebKY{;T>HNP+Y#_go(ZPM}-?7eW4i8#T z-JYBXaT(i*VzTiD|1GA@d*EMIV=Ac_b#Hh2bFJF;KSnD;mLn?oE>^^REjM}bkc&9vBeJb zE(-?&9dp91rfjj=bQ_5P2~YyO(}sdOv|l>-k_H}aid_N8_l*Uad%NZ9FUkHfjoNJR z6G_Criof^P%5PZ^kmnQo>Xz=vIv2hvXi=c*bE6;DfBEC?aoFCWD(BWQpVPSSagF0Y z#hQ;7-3d!YOdeV%&Op|ub^oB3osq~8KhBFee|h}2&ht(hkDwJAM~r2R(>#K>YQy^QlpC766nX1xofHe!W{;)>nUpH zUgD~E?au}apRtj!C_Lcb4D^2Q{F2cO4+&A@a&~?f#({0V-`V*hwPm^Y^)lino;Y{J zg_v;@5y6Vk%W$!a{X1}z?L7z^Qhg%me?FL~4!g6rqn?(ryo(5p)KBPtPvVoV zd%MgYr2QroGAA1Ivonp&vy9krl8u2M^erV*=FcVx8z0^T*RQ^g+X=-|%E5$h>qa|z zA$1Sf73|xk=veQT1p3cmY*m8&N{>|q?g4`a#VeeC4uS}Z_ zW5da}e27MAjOG=lW(Q+m)WjthG0MczR*n76V5%{>qwJtH<1XGoz3KshvK3ojI*fG#JBVQ4D%Q7Mll2WWIjHw1Wn^+HM{iWwY1)jjdoYN(LPG7 zbS2PQ$l3Yey$QCrbA8U=oXAShnt5Ww2)HsN+Rf!fHey03m5{LieeV)-yCpz(9Zq#2 z3D=H6*5f6a%Q-(c_X<;x{%+^S6SZ)*N@5lPcN7f*IjEbB?6@X?4)PMZf|9fTVpjTs z+e6d9GxHlS_ebHFM8DD@ohURSvxN;Ew|Q+3+7}ROF3u^Bq37AOv#Lg&JC+-44B*oK z6^dBYw3-1;J%*_*~!-X z+i3t>+=e$_?{_9cyL0*uoyiG6f)w|EoS(9GtB2wt3BnUafH z%*u~X{wBIC^5J4VOo5>-9r_#&M$~P_{G9t|sgNX6&eetD!>=)Y(+^>O!KtQ?x+BDX zJEn&ZBygjyr)M;&`UIEx$o+ALGOrItYhg0`Rka_L>SH4dcHv0DxXklN{swa^yvthlSJVh=RE}y`NRWg^&2iAGBY{ekqe_i8?Y*BkAbE zo$mr&-P6a_&%)R5&*v^A)As_$0@FU(%RUqYiEPB&n46wq#B%<9N!*0`_s*Ryj3JfT z9Kb@H?s|?&cjC9iox__~9L~eYNK?(c66SoBsS690WG+T58|NMHt6`iQGO569?5@<|cD+x2KUx zNY;OygzJf!t7_frbzwboXiQdS@k~vhZ#JLrP&K6b*$EJ@R{}pV+JMTp4KBdNKR`TU z$`s#O1^EJ6f2=~kgeZZ}g{xsw=K@aaNLhhtxpKOJ!dg;{I8Z!)^abxp!X(iqf}aBd z^8jb@BZX_e^h=j@E08jRbs1T9toidM__Us~J&^M#&Vs8FbCyOPrOIyWL4@e{gmmk| z*xjsE)gDM+EZ_RW4`Hl}9U#9*|H8nR5vcpkYKCc?ZCz+@gN}gGgt}b-#O@*;vELETXH#DEUq{b*aAYGCi*18 z^=G0EscS}#%gj3ed^~%Q+CgtVtzvaXgQ=Z+#pfuS;6uf z=7#TUu0T)$x&V~L7KuUKD4Lj4Mt%}s+H$k5Fg?rat(G2tYCr+Jlpx94_(?3pr%R5B zuBy6OI=cfD`W`Dm=BQN2h5Ff@DpzE=+8T0b!q4+i6ONI9=OpFfL)UnN@?%5Dt=gev z#}}G!66MU%2GSx)0)+sIS7*iKAf!Qw?M0uoA4i*7Sj3I71~q$M+haoh#sm>}&P?c? zoGzP$tGEl}4m&)jv@AC-N6qts1ZrB^6|jbN6#vLM?x>B}#)lK6qPDx;wN&$Jr}Dm+ z5t`7TYl7|T8x$)lv^>YS)a%vfOz6!$aYJ|vLmwjgFclfecOfjxPz5_lD0e-;=D`8A z0EiaA+#Rw+U)E|dXI3D&=X_Xr#!0Zx5f=v}AID}$1o@I^ffkm%&(D6Yh`vL9eM)o3 z#Qhb17rGH7nqgH4k_Ey5ywwGZoqcPf!@}`}2!-}!?dV=Cd(r}j?IXp8m8sKYgoTS6 zf=@~IS$?&gwz}dQ1JujX;fY~e^~A-EqqlcE{Pc!4>kkS%za0NX(mii~-UYQKD80`F z7oisQu-^kEEy2S^f>x?Gy;@){>uvti%)Jm@ZrkUsum$lggPqCzr~brHkq?gVZg{=0 zN20^i40O1;pP^5;6^E7`sLW}r_e$uRP=G;69gBd}fx~x+w%EU_GNc6> z;ujQ07H|o#EIzGD8O*Vm%jjcbmUG*ukGbWqIR@HN;ZfLOJlKiuiPn+|Qotk9%BZmApbLEh zy@Om|U})W`9)+<|j%Z#wj-{!TBZnWRtxRvuh_ciu=mp=qb9-Q^-Dtv9OzyKSUN1I= zzcckgKne_EN-jf9KJ#*D^3j{Ef_&40$-n5GwC5rKeR@kZqVAB&Ng!EnbUWLCkeF7E z$2Bo@at`A`D>Jz!K9R%(gX>{34sVC~<1@oA(_8;2o{XCuk6(_6g zl}7&kOxxSHoP#|N*E&tDicAtL%Y!+LX0#JdXNmpVmbNRCftSc%6TCg*>E&00HTidJ zXFFLo;l?+Tc(C3I!hMVu*=0w1;&i6$RVVj6n*s$hao7*nRF|=s(*Eu6N3d7{KoAgI z`6>G~WH^$^-0atqIx{+?q2P7S$+3^a$OzSk91Nu!||Z)ag_Uoa0GjIb3;# zSqj(VQHC-$sZKHGG@ELuKd4`LM2?$nd=&6A?FJn_^pERiMKu1#$HR;hZv>y;dm-V+ zq)e^3eFZlQh`g~Q634t~JTMKdDIlcm+y{6G&Zk+XJp&h`x&dh`@j8h zB=-gKhM#7tA)4^8QrV)ab!QRac{6U@P=|{zaVIhE@gs7@*51)e-jm9x@ow=WcfV)6 z`;R5C&$!PLSPW8ApPRgR^)l3usO3-7Q{>0-``WWFi({`2hW+ z^5Ma!f&*&y!5dzL8IJ-TFr{9yN&VZrsf5R|HxIrL%L_ z04>M{JJ^ztFV~tO5BZ9&zLd_(D7i-#pQ1N7IqpOpt^L0B#zX!V(qo{)faS5bX$_DY*jTA0x4l@qa zcm7c}nd|vdBUF8!mN9n*Xc9aJ%QX26M2bh9^slk)Z>42k+;T1nm)vtrcenVuG}E3U zYSC&6dcDGN<3?|~;K}~GO^7UU;P*C_{i9&LeHG03n_!or?LAT3)zBywex(dS{e*Qa zHIMcARe0qmJMF*OQo#w@ecVna-=qRPCiy^5j!JU#KIgXiWZyoI29`2AnVG^QZ-QSv z()Lc)5~hl*k%0E16G&2()?#P*j$`3alAO;N4drqCqPDES4Ck*D!)Q=4Z7)Lw7ufp*}yB)NRbwK{v&=R(Be838lz=Dn<=q{HVVXN_JVC@NEl>^QXmx06D&TAZE8O84ed5$aA%A(rQ;3Tn8C5U%g?ixwZI zG|2of1wUPdYKh_Y?CVptCsz6yx)+1t;HcFYDwTc|Lp(}23yYw>7~g_Eh8wQ(PvJ3!(u-r zypgBXF5{j(-Xb(iESoUsbllPizBiYkN)qu-4dEixtuW?9Nto%A3)auF-O1WgYLv>Rt#+J8p5{_sL^-Ik<~# zr5CCWP>cFkJ{nWo7xqpxF)gQdVsE#+-#J{IH%yM)n2YX+fb@eHP66e?{*>dv{gWc) zgB!n{z<(H-Y(!F-Q%%j|j_Or6o*Z;nkl6_MCQ1D3)+*+BwAoMhRwMzDuuOEZ>Q`He zD-LvJQ8Wz7$z>OiRErq|niErd2OR6@vHBZt`V>?$$1LPzeASlQ5HT$o zp5*sDQo{;+#R`NOTw0-74x)oqzBbPD3G3=*Q8!fTv7+QvwuVzDl=WR$=#253H)W4f zW5@wj`5r%4Nq!F0?mYc5!G1J*Xe_a4JmX(IKcYQMwd^C6Qin9FNN!B?p^trEypuSg z2|PSMpVSO96}Oq)at++RNh7?RYqU)UCxDm$)e#2m-2gDaEVh3M52-rb!|E_a@e7>; z1aRo5L2Cz7;EOEP`J9*;szK%wl-k%~cr!`ta^WfD@44M4H~8>bZ==iZvzF8wz|GOE zSNx&tuHV(`S6hDQWzI^|<_2e@gb?;(rCY?F=NE)cgyqXAVJSUP3rA#jeTzz2yeGpJ zA+$(F>P-Z-A~^(~!J9eL>Hg6E<=)yHX<<#?tl&fOy^Mu?Hk`Ou+ybYSKK(0}pZ>#+ z+R2a|`$CzhNfNp+8mTGK65oFL_geFJIUyxlmvZq~ZA_#?zPt%RFK9{a^NyAMVkaNz!?{nCT0Wsp* zzvh2T09>K$I6h@aV&kFakDVw@QRusKiyOxc*nbH4AH?Uma+dTqyJ}h)$Alz63OX$c zP>Gy=_?|Y%Cp6T+hQFWSCE*D($uX!p{&inPkx)xN2_V;eYH#5e*6B<&qMlXPaG?=W zp841+5*ZDr7JivgH;eP|w6~8y#p9osIk(-C(Tv`oC;|dCvVL~~DbVi_A}!yws^`oA zl7cj4#mHmD(g;n0jz>!G{oyMQQtbv40F+)8h-QisV%*{ZG;!NXW4fpqWYJr@q*%byu6ca zp|zk|HUyom$9(Y;6#hC7my}phE>gdLi==iFQXf{L;ta{IGB4o$f~30T;@~o;A^aF% zPVuUczrArWTb2g0S8TU)vP9e1n)T;IeKe2!WRFp*0cX1<+6yLo(ZOVnXixon{?wSd zE&!?GX>r2a6d4cm%Mm-3xb~ArFt)!eQOiCp`?OPQ=JtF3eX)+^)%JJwz_<2qXL#!v z^1Gj&YJ zE?C^dWbp|wA1l>lJ#pIcA5AR)70_QtpkV%W1j_j%3Oo^OHo>y>zmVLz;xqt?W`1D~l~liXdJqx*odsmqL-K!)O@_Px4 z^2H+9$ktqs`_Hn4^a|=jJobfg{_Tuc{`Zvv`ROE6qMG>)VcNHoiG)3Hx~brll-XQBbZ4TU8D<=^i;>%$1~NgR3lbYlHj-;ZeB z6JOHwFkhXC#+s6Ea$59KgK8@SL#>E2`Uy(47sh0Dt^FG~H*8l>PJ#mz6wc!PFbX)l zkBbMRUbb*N#m0Lps%c~Gw@PFeI(MAf$UO9Hkj0(g^6IDI%w?4WMisYE3`W|F>T4f|!A3Us_X7T4^z7a`PsT0CB|UHNoO2Pr!R zhEL|b3#coVO6*Uet*Q4EKL4nzZ8Uk?J}xlWJNE;Ix=HVQ_yIe70l^bh6&VDfBTI&3 zM>WW2M9VJ~hYGh)CN-)c)~mNqM1raaf=!06J6Wm>nHQbaQx-qlyL8`=+iba&#ZcPq zo=py;M1x~0jX{=a#LoPlu6X>*@2!?EOlAU^Lx|iBUzqw5p#GguKw)@v3d*^o>`15I ze9aL`U_e);5TrCw=d2%TR;a@sX#=WXj#UD(IGx>=*&#W0{uZ?3| z^Q&0`X<8IU=s_Zj56Ii%7Ko6Lsd71xZ?r-!C2P5Js>Fm?Cme*LbKx_lX@@av@8>o% zEnsQ=L&y|o&n%$2eLbMZEQJ-P<=<=iN237+;NSED<=Y?bXy6tw$~`asp4y>ev(kK9 zuf?fo`dr7CXDBkd$jocAPGEN2z)OhKQXb?IGx@cJ>$(mV;W1B(LL!W$3J2TSGGSa7 z%&{9HrE9X3M}Cm>EnO!>TGbFx(iW;!$H&pLJeIo~4qD^BKrHigtl3)nq8!cR_)|HW zO%E1ciukL}lC_M_MKr?4WFdPNuX;CvYRxlK*t@hw52eSS=%@|!vr$(*RA632g@M*c zhEiVk*_@1Lr+&lR_2K8L&zVf;tHl*dn)`*d)Z;K-6jjC4)04!5Z%?|N(NyzOdW6p9t z;_7Tq)W9d0v2NP!x~9o}WtW-S5-tt#rewyH`!T8S z>Ts3jFm6t1Ty>{MEbhy^JrrMRux6CM@;$7P%F)%Fa{5Iocj+eBiiuHdAFHp_X{@Iy z^ib%?u%yW8XdGxRqkB(U%+Z<;9Z{DaeA@WEaQa%?<>A zQz*DwnXK=Un$W2+p#<#fxjaAO+rOJVCqvwoSgOc)&jO=bgPJCLonuoi3tNgES@tn> zIAjXnICt{aBa=GJ_+*r6_@CMY1>jL-g7WMi(UndfyGsRbi1pCWBnTZh!?R*7E1xT|%E^ext7YjHrM2nco1$R?Bhp2}xUD z>gJSRT%6BD(A5ApZ(A-7Q7vf^?ul;AR?rxM&;6&aoW3mhE>1hfnblh0o1$wpiuPmf zne=cLbr|2>3VX(BpXJoVUUBh_;fSSf1mDS%=H`8yKdhb_N&5>nRQ}f2LZJu70?MoZ zh~N&>q`U74HfomX$~S+jB25F`p%5P@?_-w);t{g=7)!SZiITwA=#MwTXMwe zw@N@6i6_IQhBa=S|OGsKh1MV zVMGM?v-?6gB9->VX0m|Z53sKm3(ySF!SHU~L{^juUL5BliD_!O?f!^^@XSRA;t5vx zjCqj#nu%<|iqBSg-DN=UfXCcEp5Ib%my%oK!sMhg=6Djp&I2%?p_1!}fuN#}2B1O# zK*0k(FsZ{c?`9R9WdibDdY!%Zzb?v6U#X@n(F*P}H9bjK7!4K_?W9Q45h}_YIuq>a zuce4s8uf4aUN|B-PQoO=bQrtO!m%vbOBmnN{So}My`#Qm6_w$I1j(%ADl|Fn2s2R< zu%L7`yy6weZwjIa>}8O5IXd4AeHk(ujvoO>WD?2vn0ur3YJTVro7?l4r3?ma7)B&^PUxj zVCjtl97#&IzUw5Hwu!Rf_cG~!T%Mu?~@j?Yr zd(;d7pD{kC`70I>ySu(!`(alIzSm>RPFyRBHJkdN8dgj<8#{OOodziU{saWdvwz}I z?(c_uEL4DT_`9VMA1>~ zvDX4z-J+o@!nqWSr0{ins-M#OJOdADc-+PkiNe>+{M=`*#iB%s`j6*w|NNTX|7SV_ zKtTl_g7WMi2;PtEc6Y00N5mL^(!mAe3kCGv>dM*GqL!94E9+Lb>Or}(RvgNMSiEP> z+J4}6&gRuAroLTL_L{@Jt`81?cSDw*Cx@a+pgV$bMe!JnpA9&Rsf$cuL)K7(0G`$|3DO4@1Xm_@a+Fvx(9yR=t#gUQ18r`sc1sw|wOS7w=z0t4a55 z=~eY))qArv-pC89B_w+5@~ieB^GF0EV7#~W8B%(hoO=s5xgO=oMukI{7|#pUi$31s_DHBq3IFQKBU5Nj8Cq zBx?fK6(-3B z##c;jOw5Ka(MoXU-#&~`joox+&dr>4M8$6vAU+DyR`MRz7byJxjTe-2N92lif00o* ztiH_MOU@kQWvA~wbuLai3Ny0zWbiDl>Dl8ogg*$x0jMDa8h~nl(EwCy1VG(j0jL`h z8h|QLXaI^b0jS3Y4L}77#C12(H%(vqyLgpt5rIwe!CK+?>oYc4Z{*oow7Az~CQ`t$ zO@7zTz(FiFr|Eel`H;`@)W#__n+}x5{#K%eMyc5~-6ipud$aqY*3i;3u?K`OR@EOxaY31Sn zieh56zQ4)8Wa&G`?O7Y{d$OpJrWX^O0Ey zmcxg^=a{vd{*#sfm1_M7nhN5%V=Ix#XoCrnOI>?X#JRnhU<*PfNtd#n-?lRM^oFYK zHmk4qu~wUvaGyu?MzNC38}Jz;*`4T@^Qzb-#MEfh#?#Pp%J0X4W4a)%i={u+t`hyx zfX!0&)T=UjIXfqe@a^t1otE@suD$!#r8m42U-;Qm!uYXFwx@yNFLv2lP0MkYO+)Ha zqQ>3sS(>T~uW-D5J&hs#-Je3C_n*5bly_iu(DxNIYqd+2)GQd$%O1yR<<%w;hdXYnI(0zaGrd+oK>?6vm2 zW6~HLZvpG^E5F@FX!NdY-=j6ui=Zx!pB>X?)3gSal+VI4xgiwbG@H&OkLli%O*iSl z-Tj;@#@Kd=Y=gp-JpNm%!_s2)`@d&Pz*zkK37Bnv)+72T99c&El}%-y-_)*O*FGMF z3doLl?jRwMXEr`LAia%#u;qaSD+taofu(5=Bv|T1g2ikkSa?0d0p{08Frv?B$=kr( zOxe~x83=keI#cjMXmZ*Hi<{nE*>+UteZvN}8BkoqJ!W^ZS3=P{XRmRkp+to&ZfGQl zgzjlYUniogw1Lhuv>OLPI5grCFW3EunzS}M&}!+J*dfG9J7{Y8?kb1v0L;hv1Qf;i zf3(~p^>uW75>QVQax6tPyc}BkQP)eG3&K80iYHu*73EaXnSWr8WZ!Vz7GaXM*eMtY z+ATIdnZj@U(<%ZZ@E=bGv+a+Y?hcLHC;O@wjq57P)7Lp1TMldKIM8S`|P4{ z0FYNLXGZb5Hgk1k^0pcuqh(J)f zj#Nr@Ev2wm=bl==>BW1MeGx!Iecw=UR@XCxH-|{9Ezo32A7&(rV%o4yAD}DFDSrYT z8j;hN95fMo8{Rl#k~c>c_$SOW^~f7*le2}}8>D@-XaQfXXB&&c3>_VVU+RW&Hd9Mu zb$V+IE~+Ss??v}(L3o$IV+nQoNK~SU$Pr2MMW(HpUUpp+EtyC`c81 z(xQiM&aCn6(C!gT7how=FNu?NNXXJ`MHm%?Kq&r%<+adLQ0c}~LVT3T_JUdBDCfnh z{rjGcir59mQE!?*z6wU*|FS%ob%3ufij7HBku53i9^7m?DMZyuc?drhtWpq(ClX_q z^_N-)ykq`N4qbC|eE+AD^875 z`l@*Q$Y5JPd{?9*X5+>3Ae7E?3Ptap7$1x@uexUCMJR#5(3B@*Ta&u`LBF`Ji`h5n zk9U9(_;(cuX5U#2*uWAZEuD13Ye4zcJsb+NLt1Ph=@ zuvq7T1lwguunpmX1Y3&VywQ+pOkRPj@9|h*h}sR;WegdUrp49;CU-XqsbwVW^PFFO z{OG^JK-(RRL6F$lHd@UoX+85OGrY|9b@~Un5(Z`Hd}mVsxyF1dirC(iBY@80>lgg+ z0BU8b>L5h?+a`7DqfY=Dxye*c#+QyP6cxJf$FF!BoE$Z+k$A|(nG3}9rNiB!LxV~T z<@s{`?vUK5OKieE^N572#mF9OKuiuwBSl5<@Dp%p82|bP?5A^_1Z&b3e3%s88+PSm z7wvV4AG(BHw|5{6x}M#A2BvN>nO&<9x6t$@Zc1^FJ%(r3rc4cSSw=S+>VScaCxTL;>EJX$pTd?qk-2d zuyd+c+qG$q%3Vj>cZnFAg+3im!967!dsMU2*LDXX)K_PZebzmK?;B^Q$GYH23fOGKP$Vi^?TC4aZO*5kbO@%@&Tf;b9P-LWz1qm}Ol4k)F|a?dMS?Bm z+2#df_&f}Nnf}j7SF|3B(}UxjL__=6!Q2v#2ro=I6Qb4v^+}<~wr2(bsI!w5Bv{@8 zei1C4Ai?4o5-j9+Ai=@_00eAzBEeSTH!a*u-uTt)+GdAW5Sy<~ zo0_PsTdsHoLS?1DZku_QYGuOxH6Y^21!q1`w=JLlMk&ml^1&#{K?kw@ECCzV7Pdtv zI;IEVo}$CY%aGC(qi5#~)cD-7wd7WRl-`G`GAyCGo*9Kp2c*V{_PLzVFx=^-wjl#Q zv|0M%@PkKu$@m-k2imBCc<8_^(k5c$1;5F+9x_N0>x@9dH8))uAlgvfw|4van6HB4 z?+2WaU~7s5V@xvJ~W&B-qq)%R_i8K|=|hLba6dvMHaQqbHYG{g9>+ z=kE8;X6#8b?NA&|I{-}?&858=>yM0V(nXR3L!0b1N}CqaL(---A$Ye=??WgW$yY!( zt$&+By>)gVU+`xTfH(Kr@pNJAlUNt7?Ft zXdRAQ2U`O&NZw#n=2ds}7)Q(D;`a>9ZUl7a4i`CxE|3{6LqdU3lO2e#kqW&o*l^+nd9|Ds$=9FI>juWL6yz%gM2c+9q7am-vkGsHk zIa!O?h}IQ4Fe>J6Hs$=1uygL*q2`h3bF^^Ju|=32Id{!%QXKN*Jq2o<#K`Bi#%w0~ zk4-hBDrmD<_#588y0t?&UhsvJljQ%e@x;~;--)h*^iOfPeFd&A5-O58B$So+`Gl~hm%&v9TB2@+_RG@C zXro5>6}~}uFq2KFCw4qd6#F!0heR9)7#Ud%V z99cuW&r*6shV-3{%ayr8>Vs3?%A>I zdim9ikc1zcasymVzy*E!IQ!!}3aO3^%~{mBPWBVI-o1Xy)b;I-O|7=MhYhFUxFc#0h0yFQ-Io{%~Xn3!bObt`~ z;E1PWPBt%oC#fFQo1!hvTVS5my7tdBFPIbk0S0EopAgY27^>Lw%}1EuMnzw)H0mlMV^RT_B@gH|btV=88b8ru4LK$+GaNcA-;V=~` zz6l+e6J@E7ONtK_oi5q&NjGCvvMLdLS-9VO>W^z&#%kTbc|LRn#^1kE1(~$ zX+e#txr-26zyyQ_qVEkUURKF89L9%1cn4Q%{L1KN_tdz5!Kh1?iz%Mg{1%74MBmT* zk#i2|ehWYwzuCU<@dMJ@;DtbE$%MyrkAsbml1G{4c!O;6s~91iaPTwf#k-1r3zd1$ zSoi^6d+({$><(?fg>7o`&zTOg{JTJidrQ-(IT4B6jos~62_~fu7Q5S_R&>2uj3aIh z)&b#=t6S5w$Bq*9b?>K9PVHTOlxPtT8MZXPGFfAFDwXaLSN|UsBqSJGq^CzN?a!qGqopr{-$fm`90M68Z*Q5zI`Fx+v8km0!oi(9oVSNi zm#QbR3pUGKsm^X=B2}wE7`cDX>3G4f&^78LI8{4bbPzy8P#%`~0>1Pg)~-98tM-kX zk-bBRY}q?ADl>_!_>#S6vZJqTWs}VjDSKp7_TF2Ol@S?{J%4q)UBCDJ>-=;6Ki75c zec#V>fA0GU>#Gfks(V|>tEZzgrq@)yWN4s3ZH5^P;}S+m>Pv$kKZWt^~mrIhJ5K|Y3YIyuqK9X zEI$8XnvUKo`~a;0y}gtmXUw$mN!6E~;}-}qb5HQFE!QI@N8G%`bsp?gw(ca-k~ev7&Pa6~)eIzN7hmUW zDT-^-c4oB61Z^_5GqAww$NlFYSS?L#I+x%hCe-|4fVJMUYAESw#Ju0- zb$dvtC5T&6)aouAoieqAi9D|d(NW5R7OLW@I7PNM6#sza zgO35w3+Z>z>8z;IrGZqfKDhyiTGyPCa35B@tnQKJtiD_&2eAid1J!ZkUNSSYs&)MK_nb$buz?s&3f;c`i zIO`D0W5zr2+mwd!x|6|^CuAJy5@GpWHNR~s^t_p}?VUPNR4esX=E~z5S&$e}?O5AN z&%@)(H}5G4rPtVPqqTcWVJ-5x{n`rEgmG+!CCRCR zVKP^-GGHM7ACw}L0RP4XDBk`F(uu!pEP||i6<_%oT;9Gni!IPQwXcm&e7`8o-&tPT zlpbtRoGv`2yw)XotzveHIMnIx^W`3WRXSPQ=s8!PssI?57eu@Y(0!^#*f#uRaNE=! zeev6byT$yJhP`M{){}vI!+d)56!QIX22ODTKM~^WMV2m)gz%Mx@Fi z*~n0R8v8qm;DuZFNv9+5&QeG{E6H{?iLLu~hIvoGq#BNS7k6o>Gki*an<}e&!mjO- zMcF%FH0>+i?fh3@+n2mh(^BMpp z#^0YnF?V6It*#Gz5!sb|4f;=txZCXP^Z|Z$O<$xl`%9dZEu=NY#aj$AFJk2iv~l&~ zheIF8zsOd%QfNh(WTt_t@o3VP^n2Un-a-!{;xMpikO7ZTtR6mUQafmSN|YHNwJLr+ zX?!HVdNu#FIr82FRh=Hm0qv|MH)tM?R*|yuZmi3Ugr?=4Dq-E6?&Jqe8m!k(HY4$e zL}8rF)SqT6b>tfKm0PPL*y*=8j`~n-uG(oB^SB3vTU=NP#2m{It#9n6DEMC$Djasy zJ}V_&7A27lcq6dv^N^ea#=g#-;mJ4mtgbKP7)x#J=CCYUu{(|_+&r+*3*mlZH^vqK z60^PO5!g}YR~+>!e2whCULi=Y7B(^eYl6;i5w_=ri#x}@D=Bw}_Y(cYRHQwq=; zLCh_iW%%7ZC+nT6oe%#L=%7^j$ETnq{D1F*V*ih0aYvrS*K?G99p&9zNt>g*Td>$v zu0-TNk`p;rx%IR*6oh3PrB&v5q7L0>=*>ZzkKp{Uvt2q)OHx2iI4s=0K?$8jAoU_r~W{VzOVOGGn1h7&F@_2?pnbO+m37tUG(fb4N3+O*B3FvzSli$0)Fc zz8NsT=V^`_P=k+{b^b?>a7(r39OV_!em&cc;T_=D!NF0T5n2k8C1N5X1AFJXRkUvU zh?i`VGwxm;uZ)(>E6XSw#zeIIcGH&@b6^Cl2j-b6&fP2AJ3A*RICD_W@%Q`D#_X3g zygsM%g|Ox6ALD^i<-b!Pl%xSD?!l;xNwhOSiaJ@R-Vn99mD$KK;06%fTu`FkV98i- zLyQcAaZrjzyu+w2Ergc*2Ox%f*NN6O7uNjJcx`rSQpU{F6G7hL)HKv#jU~ zbbJ$)$L7N4op0jFeTRMCIZflGUkvZFd+2oVd?&1WvE2a#WCmz4c}Yl{8+3_svCi9z z*TJZ<=fOTj0h)+x_3cY+^ zg@sLPCzplwR9&=iyHVg2M$md@)roxi&Gjx~f;SYQ&K3b7+4|%TUHx`a=I#Y!4WdZ* z16P24x}5$s%lLKEzQ?hO`^^#kLLOQ{$e7FYjwLe7PhuNi z=oK70@DbDelc|1nnz&ut=@w2AYI>+p1PcmQN^SgWWlB2lv>0%5Tq@$6zLn4MX{+k! zy_~I+h)v;I#};MHLmbC8hU#lDVl}nApF}4Hm%o)t@u)`1stfRWNu+IDS^n^qVSv}z z?ct|CksnHxNB~N{NC1lI|K9UWS+0i>u%R##r*kFKHoUB5&Z0zLW>Wd~!|rX38LCzb zc!YG#aNn>jz9BigzCl;3J!caBWA~*Lv&r?@FT^3+Fh10b8)47xjfeh_IG+Bxkr~;2 zJibAR&zyYahpW<^e6-9Wpd~M+2Zwq#crws9J;SPEcl>-eeoq*2&?%{wpL(}79zJ5o z`0}Jp!)v-E;y#nzE@+Upg%Kv8 z_3=F6XoLyFViK|;dPhB!~{(v8$ zr1xKSK(PnD1M7|GVoH!7408^TH&$?`G20M~%6UaEt|B%w=|g4h0(vX{^9BTeZ4HH5 zL^`|hsS6oCBC%R`QJ7vYr)w+F&mBhG#t|+qn)rl|1!rEDy}(L0N(zf&{@3!pka?$_ zg~iYs5Szfxa@FSaVV-wxGiFl(!Jq~sqYT@})+%f6v?3#I7}2Pjj138#jT0QYCRjhL z53=Z!F?V;#20G?^_T3d?dzg;EBj9*`$GLL37FT1YPY{#J7TvhU!L~uILz4jgBFjq{ z?}`Pl)dl4#sor_;G5Np%XAz&~+1FVnP12Hh;gz|@MGobE_rjs1`1=zm-u{W@<&@c3 zb^Lx&-(<1Vm_^8w^o9&wW^x+Jyp$%M^R97%=wPwW7Sb;S?<`WO=oYW#WE^`9yWtZ~ z8TUz1qKJ?O!H7*TIxVlYK4QmUpm*=^j{Blfrl`7lmv=1En=I^ePSvDEKVW$D$G~5dC{+jaeP5OpH}Rj42VsG{QcU!d|C02N>Xs91;upu7-(G7A7o zgMYL^&DpC)6~Qu;txSmTSJzuzS}1W=g;Z zq-I_?@_S_Onte&~rQKm#*&B!}AMf4PJ?3EMr$iyX3u7EqeQo}k9jmKxxXvZJ?c8|m zWv%z1%uU%3=jjK*&stf)OI=AtTUiZ{{Ia_(7`T%LSB~Up=Ui5E-EuwV#r3H6VSF}^ zta<{K26Ot-M#XLWRBL%mjidP(i)$xU6r~H7ii7vTRkotFhsMn~XDLD}iZ<%q zZg{4;uG@W!2fow^Fs|76mG9*@B$#$G_~nSxqabhVcvWMxewY4SEreRI$V0T_Z&W+BG zJzbhN9^J{}`?&g`6<0cttHV2}4Hu+F&spV{ZpEmpp$}>c55tg4Zwg`H@dqL_nG9v1 z-GT?k*0=gKycy09?a}IP6%n?2X-FGG2Hw5!VgH`KBn^|84sh(K^k$7%QKHlxu{ov9 zlRN!kiG1&p3qK!`(GuLfG{*^?{gg1e?IY>TM+wQYU0jFR2duZrjG9;k1RFj9g3lFRT(CM)DV25$UPMCXk3*1`0v zG}B3BW&G=-Ps&LlUeDa~vi{RYgc9TLPoS8)@SIFl!d2-ugX4V}8OQJT=;Aj;kw0UD z>FMs%twc+;UkC9?qWlC?)+xM0isQQbN>l~QdnsCrv%@(BCC@jm;wW#zxT9!*3K2Z# zNp57b^{JV(3Ms!0?D)F|9y65q)79J z_g78j-WvB}Ii@qKAuHFT$Fz-oqu$tcmH>WX+)&hR!~{c^eEq{E-$w*bs$SB5IPpB% zZ}znHkA(B04jU*sld4@A=Xm=>=`W6cjmOClmt9`eZIAvADi(9MTV3l4*O|~;5aOzF-pv|bXGT+8*iA{lNJtNn9-|WU*i(b4&kqc+n;wo_Vmo$*EjcM3{Z^) z{0JlMU>N+MfORU}cnKs{P?Y%3C*&&A<^~yEMNYpOh^&pNA z*7dC0v)0V``S}a`d#&B%zk2}SJEB$nZUuW!nLfT|&mYyPIRpF6+mjB_k zQtZ0x!!1ymVyLXev~kM)u{}I?*RzyUDn>}f%kAwZuPR%0@23NUkCl}r<*l4{fa_V|OE;?{RT>+)fZyD`aNjvBE_+$JPu@Z2qyhSu zcKo)`IVp6{O(cBQvl`zWip$|rvcmY}oVB*q_~^K&kI!Ed6thwcGTcYjKOa58q5yD$ zi+vdn=5frPe7_*xfef7%9{$tP^U)`Rd!(OCcDK^XefaUq6HHN5RASmX#r~LncjWJZ zyzd-#I*sfRcho6x{(iqQ%Ix`_#;#eB78lOsD+XA*FP8d+MmKa`n7=uBtdH}K1DmFw zt6d&Z85i=Z@Rw15Oh)D{C~ulN#plMNXZ|YJ@^#`1Tm=4O8oyt>^C#7SA$6qUgIYn- zGYcmrjL*z4DZOg2iB)PCKKsP-gi$du?%N(#0eS!>pejk|oPm&KDrwc}kLOpKtFA1G$J*ru7Te`%%*FPiBZiDtTNp_#5EXr>`7 z%`~Q>na*&bG?TeB69P2T@fu1qWlHmY-CFB0#LaArY_Qj`NfW|%^2xVWn;)e7;&{l|u75g5 zrk_X|o-B=0C+ov|wyXWaet%x$kcyu>nBah4UXt2{g)LF@5d?VsIa}*A_Vh&e8Chw& z^YxNUuFpUuicu`TIQ-I|NqJ2*GqPpTmluueSG_y&T%*CVE72NHQ)Z_Fe!!WBa7L-0 z-#`0cr0Wht%@x7p5A?jT%c#q5vxunL?ezy0mpJh{cZyOq?Vri6soQySwSGERzH-om zap%s&t91@f&4=quVpXYlOSj64^zDIlg~iADCAEG-PlnH|?eniw3H}bKVv@C?qeJo| z>c`$$xVaHw{W`x>1+VU`Ri*=Ro33|X+V==tXTokqKkanW=fuK;PwcExHFli8VjdY9 zHZSb8>f;61u}rf0eSM}~8A>z7muA}LPu{$0XNsE4_fxl=IbiS>Xi0n4q5*@lxOYzPvQ}`6; zQl`!Ncz-Nh;(B+cVU~N-wqE3bFy!+9Z8-hqp}~qt{7o^n@D-_v>xdq{V&etF);Fkia49yg+l~C;8*R+zsdRWa zx1?K5{FrG*gE4<>yfdYYjpn}oq5S+kE6Jdq9q|)Ky~?&8Nn^RKL!zd3d71DB;0&kZ zbXJd}=1cRte zr|#b-deZn^-QGeC)2=;=qaAJjH6VcA@JsIGpo%%<L0zb(fx7MjU%WH}LP2+3TgrqUZOn zi>w|#y?E%hbM@sh^O7{M!t7C%i|GmD58rsYX`r3vQuCF0`h(RM3A)s)@?G+p_JrJ+ zP}9?zX1WU>&2*0$nrYT^nrSXonrSK|n(14tG}C8{X{LA8X{PI1n(1H*W&J-bRDcg9 zl2PO!DdoG^L+0BS&%u@#E`~M#MtC^;paQhII_?G%^+}>*7UU8$q z=;H(X^gZ0N?TWfBBYDJ{3b=z%e??C~l*>^-*itOFJeX3j^iX9vzdt_&^fpt|BS+?? zCn)!EpMWW%8a{ng>|hnOtt+@U7Lo6mN>oQ!kXBKLyMKC;EIY-|`cu0$zei*RI4P2_ zk?lySut}vxUKY#}7EET+K1oJzb)T5GR#63 zOeF;gxZ^6CXrN(;lt^_?5?f6gtOz=w(^n>uyC(>H$=3G#`zAO(7AP*by$-$cT_BEN zu42+*x7IuI#z)2KM2fO%Ib3vX`p9ct+-!(tteEW4<-A{aAaCk*ZequURaH&=!4|rL zlkHM!Vp8&nf~2mpdZK~Ey=mX97D)g%@K^}&cucYIU{bbi@!_QpSnh~{*H31nTtVGi zWi@0KF;`f!jPDlFs_CObyL+9OxtDBQi%oosOfGJkJyh#0ikrm(#}vb z4C5}ZkDrqvz*H2WKz0@TD3Ct_NP+wjU_1&ArN7!~WR79P^ZJB18RASu00pwE*tuYv zK6Ky9yZ! z0{Q>q7yW0(hwcPJnOVq*v6MWGeFIRflS1Q7$~Oqssk zW}S}da+7n83)upa`6n92koUI_Z3b^$HR$W@ByVr%?=`+V0*sB%QZ?ZpkoEDE*0Qiw zGG7`4Dcw7;9Gb&d4wbgKIcoC!ZdnihuGEwK`$^)0nn`rue>w}caUc$Nxxg8LmEx-S ztW=D44qJ%*v|37KboH*$^{lp5);5)28M0ZwwiTW}=?Jxq#uQa6&{ha3UnZ|ki>TwO zT9vj~5qTCgJ=#cp;p~}j2J8abqMqN#Hmm&pLT@)(S-o=aEbAXjcGm?`)5Y441>{gs ziKn577AKqK*0`(v^Ye*ZVF_0Atn^&-`m6ATuoaHg*#0*SVZ4s@G1@nP&JTHap)}pc z%BIPuA>c*(=6&?jRz+9*{k@gTjlE)9xrV&?7?#s`+b6$kV5^m@^=(5qdj4%PB(ZtM z=BeMHmRBZ&K;_f)ff>}^_CYm_pm!BR}5A&L2W_YgD=7{EI^X!QM zb*}`#8v9u?iw}&(oGu_;{6q0WseTdf22oXho&{SA3ASYWYx<^!Zuv3&X;6vj30hmL zP!hyiv4dK(@E0b)UgF^+DHo2>$HtA)=wmCO$&n0i1&12(#?GR9MY-Wyi)n|Wr+ER&{zbp`He=AQs>s~aKkZ-+%u+2n%&xZus6X>SJycS;9=wB5xaHa+3=kTN3kO0S0^vK zxlPUX(_QA@Q)5E|)*=~>SDf0kGM?X#iO_;Q0F>X1SMmyHJk)vg$vOI>@g}$N{F_@q zCf(Uh4*k9f^I0fX&iK|i4r+hATrMHHeDBp&K6^?^%pf0h7ICF!_|CuKKFwA<(7@HPf^ciuwL3{C*IWYFb=pYS*YG0SAx9+q=Fle`FV3rd=dBQt zCP`?#5PfC~yUL}mZ+@$}li^;T>iyG6?^c-b3 z=V*sw24FETSmh9*nl<}O8d*cOvwlq&!YTAGihG}*`m1ur!ovBnX&W=zr`o=c30@C*OW}osDii4p>3Nq{*Y%Cn z(Q~pk0Yk_ z<~uan58-lh!M7tsJr%ov(Ht9Ch0jI<^+T82yKxM&GH)gxlZz>BF*Y_-JGJraM9?rC zPO42l#VX;XPUl>)YX5mhEG6Z~i< zUhsb-|2TuctpQ1nhwp>7_vnQM*9K^~l$113>*>dz*^t#4 zdBEp?otGU?G!>SJ?9+IGo41-cc_nBz=GGJ8{J7#^G5umA{ETlwE_kq&$QhWz4Z5An ztZV|UJ2*)~-hOO7enQ3d2T6*S(@@@4y&)s38x%aT%^y4w;CFVEG$bU}a^seHybjPi h`;z!MfZ8t6Kz#5->^hY1KNfRIu@<)F#y2X+_iu@>7%>0< 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..a55ad27f20a 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.SnappableSegmentedKeyValueStorageAdapter; 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 SnappableSegmentedKeyValueStorageAdapter<>( + KeyValueSegmentIdentifier.BLOCKCHAIN, optimisticRocksDBColumnarKeyValueStorage); + final ExecutionContextTestFixture executionContext = ExecutionContextTestFixture.builder().blockchainKeyValueStorage(keyValueStorage).build(); final MutableBlockchain blockchain = executionContext.getBlockchain(); 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..042fdd15d3f 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 @@ -38,7 +38,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; @@ -96,7 +96,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..45eefc67182 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 @@ -30,7 +30,6 @@ 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; @@ -50,7 +49,7 @@ 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; @@ -58,7 +57,6 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private Integer databaseVersion; private Boolean isSegmentIsolationSupported; private RocksDBColumnarKeyValueStorage segmentedStorage; - private KeyValueStorage unsegmentedStorage; private RocksDBConfiguration rocksDBConfiguration; private final Supplier configuration; @@ -163,17 +161,7 @@ public KeyValueStorage create( // 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() @@ -249,7 +237,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 +271,6 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr @Override public void close() throws IOException { - if (unsegmentedStorage != null) { - unsegmentedStorage.close(); - } if (segmentedStorage != null) { segmentedStorage.close(); } 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/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/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/unsegmented/RocksDBTransaction.java deleted file mode 100644 index ffd5a1596f6..00000000000 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/unsegmented/RocksDBTransaction.java +++ /dev/null @@ -1,112 +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 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.rocksdb.RocksDBException; -import org.rocksdb.Transaction; -import org.rocksdb.WriteOptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** The RocksDb transaction. */ -public class RocksDBTransaction implements KeyValueStorageTransaction { - 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; - - /** - * Instantiates a new RocksDb transaction. - * - * @param innerTx the inner tx - * @param options the options - * @param metrics the metrics - */ - RocksDBTransaction( - final Transaction innerTx, final WriteOptions options, final RocksDBMetrics metrics) { - this.innerTx = innerTx; - this.options = options; - this.metrics = metrics; - } - - @Override - public void put(final byte[] key, final byte[] value) { - try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { - innerTx.put(key, value); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } - } - - @Override - public void remove(final byte[] key) { - try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { - innerTx.delete(key); - } catch (final RocksDBException e) { - if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } - } - - @Override - public 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)) { - logger.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)) { - logger.error(e.getMessage()); - System.exit(0); - } - throw new StorageException(e); - } finally { - close(); - } - } - - private void close() { - innerTx.close(); - options.close(); - } -} 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..19ee5c197ec 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 @@ -48,7 +48,7 @@ public class RocksDBKeyValuePrivacyStorageFactoryTest { @Mock private SegmentIdentifier segment; @Test - public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception { + public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); final Path tempPrivateDatabaseDir = tempDatabaseDir.resolve("private"); @@ -69,9 +69,10 @@ 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 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..9a3fd3ade53 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 @@ -71,7 +71,7 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { } @Test - public void shouldDetectVersion0DatabaseIfNoMetadataFileFound() throws Exception { + public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { final Path tempDataDir = temporaryFolder.newFolder().toPath().resolve("data"); final Path tempDatabaseDir = temporaryFolder.newFolder().toPath().resolve("db"); Files.createDirectories(tempDatabaseDir); @@ -85,7 +85,7 @@ 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 @@ -118,14 +118,14 @@ 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); } 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..ba65b62ff64 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,6 +15,7 @@ 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.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; @@ -26,7 +27,10 @@ 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 { @@ -55,4 +59,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..e342d6ddcb1 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,9 +16,21 @@ 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; @@ -33,13 +45,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 @@ -257,6 +277,80 @@ 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 SnappableSegmentedKeyValueStorageAdapter<>(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}), @@ -302,6 +396,12 @@ protected abstract SegmentedKeyValueStorage createSegm final List segments, final List ignorableSegments); + 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()); 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..5633de159d8 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,6 +15,7 @@ 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.rocksdb.RocksDBMetricsFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDbSegmentIdentifier; @@ -25,6 +26,10 @@ 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 { @@ -51,4 +56,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 TransactionDBRocksDBColumnarKeyValueStorage( + new RocksDBConfigurationBuilder().databaseDir(path).build(), + segments, + ignorableSegments, + metricsSystem, + RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); + } } From 407f84a98bfcf19025ac68c895a40a82dee79f17 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Tue, 18 Jul 2023 01:32:24 +1000 Subject: [PATCH 10/51] Plugins migrate to junit5 (#5703) * Migrate util module to JUnit 5.0 Signed-off-by: 7suyash7 * Migrate plugins to Junit 5.0 Signed-off-by: 7suyash7 * refactor tests Signed-off-by: 7suyash7 * removed file properly Signed-off-by: Sally MacFarlane --------- Signed-off-by: 7suyash7 Signed-off-by: Sally MacFarlane Co-authored-by: 7suyash7 --- plugins/rocksdb/build.gradle | 6 +-- .../rocksdb/RocksDBCLIOptionsTest.java | 2 +- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 25 +++++----- .../RocksDBKeyValueStorageFactoryTest.java | 49 +++++++++---------- .../storage/rocksdb/RocksDBMetricsTest.java | 16 +++--- .../configuration/DatabaseMetadataTest.java | 22 ++++----- ...nDBRocksDBColumnarKeyValueStorageTest.java | 4 +- .../RocksDBColumnarKeyValueStorageTest.java | 3 +- ...nDBRocksDBColumnarKeyValueStorageTest.java | 2 +- 9 files changed, 61 insertions(+), 68 deletions(-) diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index 95e9b5087a3..f76e8d80ae0 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -51,11 +51,11 @@ dependencies { 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/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 19ee5c197ec..c72052d7604 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 @@ -28,29 +28,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; @Test public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() 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"); final Path tempPrivateDatabaseDir = tempDatabaseDir.resolve("private"); Files.createDirectories(tempPrivateDatabaseDir); Files.createDirectories(tempDataDir); @@ -77,8 +76,8 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception @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); @@ -103,8 +102,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 9a3fd3ade53..9061e28c3ec 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 @@ -32,14 +32,13 @@ 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 +46,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; @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); @@ -72,8 +71,8 @@ public void shouldCreateCorrectMetadataFileForLatestVersion() throws Exception { @Test public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() 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); @@ -90,8 +89,8 @@ public void shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception @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 +108,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); @@ -131,8 +130,8 @@ public void shouldDetectCorrectVersionInCaseOfRollback() throws Exception { @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 +149,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 +165,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 +201,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 ba65b62ff64..3a292acfec3 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 @@ -22,11 +22,11 @@ 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; @@ -39,7 +39,7 @@ protected SegmentedKeyValueStorage createSegmentedStor 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(), 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 e342d6ddcb1..7605b919e16 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 @@ -214,8 +214,9 @@ 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 = createSegmentedStore( 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 5633de159d8..3d880fbc770 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 @@ -50,7 +50,7 @@ protected SegmentedKeyValueStorage createSegmentedStor final List segments, final List ignorableSegments) { return new TransactionDBRocksDBColumnarKeyValueStorage( - new RocksDBConfigurationBuilder().databaseDir(path).build(), + new RocksDBConfigurationBuilder().databaseDir(folder).build(), segments, ignorableSegments, new NoOpMetricsSystem(), From 03ff68804370519c4c27a51af592ed7da6d6805f Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 18 Jul 2023 17:47:54 -0600 Subject: [PATCH 11/51] Changes to allow evmtool t8n-server to work with execution-spec-tests (#5701) An omnibus of minor changes needed for t8n-server to work with the EFs new execution-spec-tests framework * Reduce logging output * Fix json library mismatch between t8n and t8n-server * Add hook to enumerate supported forks * temporarily map Shanghai+6780 to Cancun * add to main distro under 'evmtool' name * No longer support the "protected" attribute in TXes Signed-off-by: Danno Ferrin --- CHANGELOG.md | 1 + build.gradle | 9 +- .../besu/evmtool/B11rSubCommand.java | 2 + .../besu/evmtool/EvmToolCommand.java | 2 + .../besu/evmtool/StateTestSubCommand.java | 2 + .../hyperledger/besu/evmtool/T8nExecutor.java | 33 +-- .../besu/evmtool/T8nServerSubCommand.java | 211 +++++++++++------- .../besu/evmtool/T8nSubCommand.java | 2 + .../besu/evmtool/t8n/shanghai-init-code.json | 7 +- .../t8n/shanghai-withdrawals-no-nonce.json | 8 +- .../evmtool/t8n/shanghai-withdrawals.json | 8 +- .../ReferenceTestProtocolSchedules.java | 2 + .../besu/util/LogConfigurator.java | 4 + 13 files changed, 173 insertions(+), 118 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e42706754..aa4659f4d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Removed support for version 0 of the database as it is no longer used by any active node. ### 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) 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/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..edd274088b7 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 @@ -23,6 +23,7 @@ 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 +153,7 @@ public B11rSubCommand(final EvmToolCommand parentCommand) { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final ObjectReader b11rReader = objectMapper.reader(); 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..a73ccd49c6c 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 @@ -43,6 +43,7 @@ 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; @@ -283,6 +284,7 @@ private static void addForkHelp(final CommandLine subCommandLine) { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); try { final EvmToolComponent component = DaggerEvmToolComponent.builder() 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..8d624449258 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 @@ -44,6 +44,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; @@ -98,6 +99,7 @@ public StateTestSubCommand() { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); final ObjectMapper stateTestMapper = JsonUtils.createObjectMapper(); final JavaType javaType = diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index c3838237858..e83f51fe822 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -15,6 +15,9 @@ */ package org.hyperledger.besu.evmtool; +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_BASE; +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_MIN; +import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE; import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts; import org.hyperledger.besu.config.StubGenesisConfigOptions; @@ -104,6 +107,9 @@ protected static List extractTransactions( } 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()); @@ -129,16 +135,11 @@ protected static List extractTransactions( if (txNode.has("to")) { builder.to(Address.fromHexString(txNode.get("to").textValue())); } - - if (transactionType.requiresChainId() - || !txNode.has("protected") - || txNode.get("protected").booleanValue()) { + BigInteger v = + Bytes.fromHexStringLenient(txNode.get("v").textValue()).toUnsignedBigInteger(); + if (transactionType.requiresChainId() || (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0)) { // chainid if protected - builder.chainId( - new BigInteger( - 1, - Bytes.fromHexStringLenient(txNode.get("chainId").textValue()) - .toArrayUnsafe())); + builder.chainId(chainId); } if (txNode.has("accessList")) { @@ -190,12 +191,14 @@ protected static List extractTransactions( transactions.add(builder.signAndBuild(keys)); } else { - BigInteger v = - Bytes.fromHexStringLenient(txNode.get("v").textValue()).toUnsignedBigInteger(); - if (v.compareTo(BigInteger.valueOf(35)) >= 0) { - v = v.subtract(BigInteger.valueOf(35)).mod(BigInteger.TWO); - } else if (v.compareTo(BigInteger.valueOf(27)) >= 0) { - v = v.subtract(BigInteger.valueOf(27)).mod(BigInteger.TWO); + 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() 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 5bbf3199075..fc1c08ad5c9 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 @@ -21,6 +21,7 @@ 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.evm.EvmSpecVersion; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; import org.hyperledger.besu.util.LogConfigurator; @@ -33,11 +34,14 @@ 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 io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.http.HttpServerRequest; import picocli.CommandLine; @CommandLine.Command( @@ -60,95 +64,132 @@ public class T8nServerSubCommand implements Runnable { public void run() { LogConfigurator.setLevel("", "OFF"); Vertx.vertx() - .createHttpServer() - .requestHandler( - req -> - req.bodyHandler( - body -> { - ObjectMapper objectMapper = JsonUtils.createObjectMapper(); - 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 = new ArrayList<>(); - List rejections = new ArrayList<>(); - Object txs = input.getValue("txs"); - if (txs != null) { - if (txs instanceof JsonArray txsArray) { - extractTransactions( - new PrintWriter(System.err, true, StandardCharsets.UTF_8), - txsArray.stream().map(s -> (JsonNode) s).iterator(), - transactions, - rejections); - } else if (txs instanceof String tx) { - transactions = - extractTransactions( - new PrintWriter(System.err, true, StandardCharsets.UTF_8), - List.of(new TextNode(removeSurrounding("\"", tx))) - .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 { - 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 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()); + 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) { + t.printStackTrace(); + throw t; + } + } + + 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 dbf5a59756c..efcb3b71043 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 @@ -27,6 +27,7 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.StandardJsonTracer; import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; +import org.hyperledger.besu.util.LogConfigurator; import java.io.FileOutputStream; import java.io.FileReader; @@ -167,6 +168,7 @@ public T8nSubCommand(final EvmToolCommand parentCommand) { @Override public void run() { + LogConfigurator.setLevel("", "OFF"); final ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final ObjectReader t8nReader = objectMapper.reader(); 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 d33e96bfd53..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": { 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 3bf5beaae52..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": { 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 046a9194cdf..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": { 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 4f5a7d7b7c2..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 @@ -78,6 +78,8 @@ public static ReferenceTestProtocolSchedules create(final StubGenesisConfigOptio "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/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 From 1a087709acef317f234256c5f3d6bc5ab3785933 Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Thu, 20 Jul 2023 13:17:24 +0200 Subject: [PATCH 12/51] Extend OperationTracer with new methods (#5662) * Extend OperationTracer with new methods, create Signed-off-by: Daniel Lehrner * Rename ExtendedOperationTracer to BlockAwareOperationTracer Signed-off-by: Daniel Lehrner * fixed plugin api hash Signed-off-by: Daniel Lehrner * added missing javadoc comments Signed-off-by: Daniel Lehrner * Update evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Only update peer with the first and last block (#5659) * only update peer with the first and last block Signed-off-by: Stefan Signed-off-by: Daniel Lehrner * Put download links into CHANGELOG and do some clean up (#5660) * put the download links for 23.4.4 into the CHANGELOG.md * clean up CHANGELOG Signed-off-by: Stefan Signed-off-by: Daniel Lehrner * Add --amend to docker manifest create to fix docker latest tag (#5661) We need to replace previous release's latest tag. Might be broken due to a recent change in the docker command implementation Signed-off-by: Simon Dudley Signed-off-by: Daniel Lehrner * Add Xlayered-tx-pool to the config log printout (#5665) Unrelated: clarify epoch length in javadoc Signed-off-by: Simon Dudley Co-authored-by: Gabriel Fukushima Signed-off-by: Daniel Lehrner * Add hooks to AbstractCreateOperation for library users (#5656) Add hooks for a successful contract create, a failed contract create, and an invalid contact create. Users of the library will be able to customize create responses without having to replace core logic. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Test updates for cancun execution-spec-tests (#5670) - support legacy V values (larger V value) and type 1+ (v is recId only) - new fields - shared transaction extraction - rejection detection Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Upgrade BouncyCastle libraries (#5675) Upgrade bouncy castle to v1.75. This involved a change in maven coordinates for other modules. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Introduce transaction validator interface (phase 1) (#5673) Signed-off-by: Fabio Di Fabio Signed-off-by: Daniel Lehrner * Only validate `--miner-enabled` option for ethash networks (#5669) * Modify the min-gas-price option validation * Check for whether ethash is in use, either from genesis or network config, and use that for miner checks * Add genesis configuration isPoa() convenience function --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead Co-authored-by: Simon Dudley Signed-off-by: Simon Dudley Signed-off-by: Daniel Lehrner * Update tuweni2.4.2 (#5684) * Revert "Revert "Update Tuweni to 2.4.1 (#5513)" (#5585)" This reverts commit 6111e1bbc36f6b8b19780412cc61f849b639e350. Signed-off-by: Antoine Toulme * update Tuweni to 2.4.2 Signed-off-by: Antoine Toulme --------- Signed-off-by: Antoine Toulme Signed-off-by: Daniel Lehrner * Do not leak references to PendingTransactions (#5693) Signed-off-by: Fabio Di Fabio Signed-off-by: Daniel Lehrner * remove v0 version of the database (#5698) Signed-off-by: Karim TAAM Signed-off-by: Daniel Lehrner * updated plugin api hash Signed-off-by: Daniel Lehrner * spotless Signed-off-by: Daniel Lehrner * updating plugin api hash Signed-off-by: Daniel Lehrner * moved transcation interface to datatypes to use it in the OperationTracer.traceStartTransaction method Signed-off-by: Daniel Lehrner * fix import Signed-off-by: Daniel Lehrner --------- Signed-off-by: Daniel Lehrner Signed-off-by: Stefan Signed-off-by: Simon Dudley Signed-off-by: Danno Ferrin Signed-off-by: Fabio Di Fabio Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead Signed-off-by: Antoine Toulme Signed-off-by: Karim TAAM Co-authored-by: Sally MacFarlane Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Co-authored-by: Simon Dudley Co-authored-by: Gabriel Fukushima Co-authored-by: Danno Ferrin Co-authored-by: Fabio Di Fabio Co-authored-by: Matt Whitehead Co-authored-by: Antoine Toulme Co-authored-by: matkt --- .../account/AccountTransactions.java | 2 +- .../account/TransferTransaction.java | 2 +- .../account/TransferTransactionBuilder.java | 2 +- .../TestPrivacyPluginPayloadProvider.java | 2 +- ...igningPrivateMarkerTransactionFactory.java | 2 +- .../besu/services/TraceServiceImpl.java | 20 +++- .../hyperledger/besu/PrivacyReorgTest.java | 2 +- .../besu/services/BesuEventsImplTest.java | 2 +- .../besu/datatypes}/Transaction.java | 11 +- .../besu/datatypes}/TransactionType.java | 2 +- .../api/jsonrpc/JsonRpcResponseUtils.java | 2 +- .../EthGetBlockByHashIntegrationTest.java | 2 +- .../EthGetBlockByNumberIntegrationTest.java | 2 +- .../EthGetFilterChangesIntegrationTest.java | 2 +- .../EthGetFilterChangesIntegrationTest.java | 2 +- .../eea/AbstractEeaSendRawTransaction.java | 2 +- .../results/TransactionCompleteResult.java | 2 +- .../results/TransactionPendingResult.java | 2 +- .../results/TransactionReceiptResult.java | 2 +- .../AbstractEthGraphQLHttpServiceTest.java | 2 +- .../methods/EthGetTransactionByHashTest.java | 2 +- .../methods/EthGetTransactionReceiptTest.java | 2 +- .../TransactionCompleteResultTest.java | 2 +- .../blockcreation/AbstractBlockCreator.java | 2 +- .../BlockTransactionSelector.java | 2 +- .../AbstractBlockTransactionSelectorTest.java | 2 +- .../vm/TraceTransactionIntegrationTest.java | 2 +- .../besu/ethereum/core/Transaction.java | 4 +- .../ethereum/core/TransactionReceipt.java | 2 +- .../core/encoding/TransactionDecoder.java | 2 +- .../core/encoding/TransactionEncoder.java | 2 +- .../mainnet/AbstractBlockProcessor.java | 2 +- .../mainnet/ClassicProtocolSpecs.java | 2 +- .../mainnet/MainnetProtocolSpecs.java | 2 +- .../mainnet/MainnetTransactionValidator.java | 2 +- ...igningPrivateMarkerTransactionFactory.java | 2 +- .../ethereum/core/BlockDataGenerator.java | 2 +- .../core/PrivateTransactionDataFixture.java | 2 +- .../ethereum/core/TransactionTestFixture.java | 2 +- .../core/BlockValueCalculatorTest.java | 2 +- .../ethereum/core/TransactionBuilderTest.java | 2 +- .../TransactionPriceCalculatorTest.java | 8 +- .../BaseFeeBlockBodyValidatorTest.java | 2 +- .../MainnetTransactionValidatorTest.java | 2 +- .../feemarket/LondonFeeMarketTest.java | 2 +- .../feemarket/ZeroBaseFeeMarketTest.java | 2 +- .../PrivacyPluginPrecompiledContractTest.java | 2 +- ...ngPrivateMarkerTransactionFactoryTest.java | 2 +- ...ngPrivateMarkerTransactionFactoryTest.java | 2 +- .../PrivateStorageMigrationTest.java | 2 +- .../transaction/TransactionSimulatorTest.java | 2 +- .../TransactionAnnouncementDecoder.java | 2 +- .../TransactionAnnouncementEncoder.java | 2 +- .../transactions/TransactionAnnouncement.java | 2 +- .../transactions/TransactionBroadcaster.java | 4 +- .../eth/transactions/TransactionPool.java | 2 +- .../eth/messages/MessageWrapperTest.java | 2 +- .../PooledTransactionsMessageTest.java | 2 +- .../backwardsync/BackwardSyncContextTest.java | 2 +- ...TransactionHashesMessageProcessorTest.java | 2 +- ...ingTransactionEstimatedMemorySizeTest.java | 2 +- .../TransactionBroadcasterTest.java | 4 +- .../TransactionPoolLegacyTest.java | 2 +- .../TransactionPoolLondonTest.java | 2 +- ...TransactionPoolReplacementHandlerTest.java | 2 +- .../TransactionReplacementRulesTest.java | 2 +- .../BaseFeePrioritizedTransactionsTest.java | 6 +- .../layered/BaseTransactionPoolTest.java | 2 +- .../LayeredPendingTransactionsLegacyTest.java | 2 +- .../LayeredPendingTransactionsLondonTest.java | 2 +- .../BaseFeePendingTransactionsTest.java | 2 +- .../hyperledger/besu/evmtool/T8nExecutor.java | 2 +- ...AccountPermissioningControllerFactory.java | 2 +- ...rtContractPermissioningControllerTest.java | 2 +- .../processor/ContractCreationProcessor.java | 3 + .../besu/evm/tracing/OperationTracer.java | 17 +++ .../tracing/ExtendedOperationTracerTest.java | 107 ++++++++++++++++++ plugin-api/build.gradle | 2 +- .../besu/plugin/data/BlockBody.java | 1 + .../UnsignedPrivateMarkerTransaction.java | 1 + .../besu/plugin/services/BesuEvents.java | 2 +- .../besu/plugin/services/TraceService.java | 6 +- .../privacy/PrivacyPluginPayloadProvider.java | 2 +- .../tracer/BlockAwareOperationTracer.java | 47 ++++++++ .../txselection/TransactionSelector.java | 2 +- 85 files changed, 280 insertions(+), 101 deletions(-) rename {plugin-api/src/main/java/org/hyperledger/besu/plugin/data => datatypes/src/main/java/org/hyperledger/besu/datatypes}/Transaction.java (95%) rename {plugin-api/src/main/java/org/hyperledger/besu/plugin/data => datatypes/src/main/java/org/hyperledger/besu/datatypes}/TransactionType.java (98%) create mode 100644 evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/tracer/BlockAwareOperationTracer.java 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/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java index 321996d51ea..aa8cc6b71bd 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java @@ -30,9 +30,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 +68,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 +81,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 +100,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() @@ -114,6 +117,9 @@ private void trace(final Block block, final OperationTracer tracer) { maybeParentHeader .flatMap(BlockHeader::getExcessDataGas) .orElse(DataGas.ZERO)); + + tracer.traceStartTransaction(transaction); + final TransactionProcessingResult result = transactionProcessor.processTransaction( blockchain, @@ -125,9 +131,15 @@ private void trace(final Block block, final OperationTracer tracer) { new CachingBlockHashLookup(header, blockchain), false, dataGasPrice); + + 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/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 68170f3258c..75c9b1286e1 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; @@ -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; 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 95% 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..40cd95ab3b8 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,7 +68,6 @@ default Optional getMaxPriorityFeePerGas() { * * @return the quantity of Wei for fee cap. */ - @Unstable default Optional getMaxFeePerGas() { return Optional.empty(); } @@ -85,7 +78,6 @@ default Optional getMaxFeePerGas() { * * @return the quantity of Wei for fee per data gas. */ - @Unstable default Optional getMaxFeePerDataGas() { 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 98% 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..26c94994c64 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; 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..3f87d924a9d 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; 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..3347b6f93eb 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; @@ -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; 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..9a78e361dde 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; @@ -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; 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..10d57b929ee 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 @@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.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; @@ -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; 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..44d9b69f6d6 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,11 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; +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.Transaction; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; 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..4f79320ecf2 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 @@ -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.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.util.List; 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..701f8e3064b 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; 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 e752dcb8242..285094cc369 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 @@ -16,6 +16,7 @@ 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; @@ -35,7 +36,6 @@ 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.util.Collections; 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 b8ac917718a..bf065c27bc4 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,6 +21,7 @@ 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; @@ -34,7 +35,6 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; -import org.hyperledger.besu.plugin.data.Transaction; import java.util.Optional; import java.util.Set; 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 8ea908e5889..6a2dbc67c4b 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 @@ -22,6 +22,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.GasLimitCalculator; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; @@ -40,7 +41,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.Collections; 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..75fd883eba5 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; 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 cb3e1860b92..55f0ccc3cb7 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 @@ -17,6 +17,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.DataGas; 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; @@ -47,7 +48,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; diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 84e87a5857e..6675973a43d 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.blockcreation; import org.hyperledger.besu.datatypes.Address; +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; @@ -37,7 +38,6 @@ import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.txselection.TransactionSelector; import org.hyperledger.besu.plugin.services.txselection.TransactionSelectorFactory; 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 29d03d0f4b3..16a6c540d47 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 @@ -25,6 +25,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.GasLimitCalculator; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -61,7 +62,6 @@ 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.services.kvstore.InMemoryKeyValueStorage; 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/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 3a444e5528f..bb86c9491a5 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 @@ -26,6 +26,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Quantity; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; @@ -34,7 +35,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 +52,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 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/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java index bd41e0276bf..e3ba2dc4736 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; 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..f511a917a91 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 @@ -18,12 +18,12 @@ 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.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; 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..3a18429aba0 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 @@ -16,6 +16,7 @@ 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 +37,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; 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 4aa97733f9c..6755d5f6bf7 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,6 +17,7 @@ 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; @@ -37,7 +38,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; 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 e5b7a032bae..1e94b9e04c2 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,6 +17,7 @@ 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; @@ -59,7 +60,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; 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 710e24601fd..28ad446e9c1 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 @@ -19,6 +19,7 @@ import org.hyperledger.besu.crypto.SECPSignature; 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.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; @@ -27,7 +28,6 @@ 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.Optional; 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/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..73ecabeee4c 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,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.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -36,7 +37,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; 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 79307d2ebdc..60e80112895 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 @@ -17,9 +17,9 @@ import org.hyperledger.besu.crypto.KeyPair; 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.evm.AccessListEntry; -import org.hyperledger.besu.plugin.data.TransactionType; import java.math.BigInteger; import java.util.List; 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..0a4c3aad964 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,8 +18,8 @@ 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; 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..e6bc265918c 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; 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..57308aff27d 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,13 +15,13 @@ 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; 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..7dee20bab8c 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,13 +20,13 @@ 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; 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 672b93c5edf..34fc7f1d804 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 @@ -33,6 +33,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.GasLimitCalculator; import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; @@ -42,7 +43,6 @@ 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.Optional; 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..4c304ce712b 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,10 +18,10 @@ 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; 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..4892bceb1fd 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 @@ -19,10 +19,10 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.DataGas; +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; 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..d1156abd175 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 @@ -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/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java index 48c6e33bbb8..641d4ffce65 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,11 +20,11 @@ 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; 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..f425eaf39bf 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,10 +18,10 @@ 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; 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..c6b0352eff6 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; 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..8962ef56c9c 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; 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/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 f1c28413544..18eaf4cf6c3 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 @@ -21,6 +21,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.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; @@ -41,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; 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..be86b802e65 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; 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..6a5b8344c51 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,10 +18,10 @@ 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; 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..eb9f9dc54bb 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; 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..c3a609ef292 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; 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/TransactionBroadcasterTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcasterTest.java index 52193c74037..8664b0082d9 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; 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..0fa5df961cf 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,9 +21,9 @@ 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; 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..c4097ca85da 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,10 +20,10 @@ 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; 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 b594d7a258b..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; 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..83bce273019 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,7 +38,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.math.BigInteger; import java.util.List; 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..87d7c650b2f 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; 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/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index e83f51fe822..2327a779c1f 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; +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.BlockHeaderBuilder; @@ -53,7 +54,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evmtool.exception.UnsupportedForkException; -import org.hyperledger.besu.plugin.data.TransactionType; import java.io.IOException; import java.io.PrintWriter; 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..2de2b846657 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,6 +18,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.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Transaction; @@ -28,7 +29,6 @@ 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; 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..a7f01997d49 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; 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..58f809aee64 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 @@ -175,6 +175,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/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/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/plugin-api/build.gradle b/plugin-api/build.gradle index eef486e6c7b..58995ab2a51 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -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 = 'd2bQ74zD+rKQgzZO97OO2976iJ3ho5dF2ZX4NM+Zt38=' } 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/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/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; From 47a61ddb1185e400520e0ae9fa9cfd0b577d4fc1 Mon Sep 17 00:00:00 2001 From: George Tebrean <99179176+gtebrean@users.noreply.github.com> Date: Mon, 24 Jul 2023 03:22:46 +0300 Subject: [PATCH 13/51] Decouple JsonRpcError enum from the data field (#5629) Signed-off-by: George Tebrean Co-authored-by: Simon Dudley Signed-off-by: Simon Dudley --- CHANGELOG.md | 1 + .../condition/priv/ExpectJsonRpcError.java | 5 + .../dsl/condition/priv/PrivConditions.java | 4 +- .../privacy/EnclaveErrorAcceptanceTest.java | 8 +- ...tiTenancyValidationFailAcceptanceTest.java | 14 +- .../jsonrpc/methods/CliqueGetSigners.java | 4 +- .../methods/CliqueGetSignersAtHash.java | 4 +- .../clique/jsonrpc/methods/Propose.java | 4 +- .../methods/CliqueGetSignersAtHashTest.java | 4 +- .../jsonrpc/methods/CliqueGetSignersTest.java | 4 +- .../clique/jsonrpc/methods/ProposeTest.java | 6 +- .../AbstractGetSignerMetricsMethod.java | 4 +- .../jsonrpc/AbstractVoteProposerMethod.java | 4 +- .../AbstractVoteProposerMethodTest.java | 4 +- .../methods/QbftDiscardValidatorVote.java | 4 +- .../methods/QbftProposeValidatorVote.java | 4 +- .../methods/QbftDiscardValidatorVoteTest.java | 4 +- .../methods/QbftProposeValidatorVoteTest.java | 4 +- .../fork/frontier/EthCallIntegrationTest.java | 10 +- .../EthEstimateGasIntegrationTest.java | 4 +- .../EthGetFilterChangesIntegrationTest.java | 8 +- .../fork/london/EthCallIntegrationTest.java | 12 +- .../EthGetFilterChangesIntegrationTest.java | 8 +- .../api/handlers/AbstractJsonRpcExecutor.java | 6 +- .../api/handlers/AuthenticationHandler.java | 4 +- .../api/handlers/JsonRpcArrayExecutor.java | 6 +- .../api/handlers/JsonRpcExecutorHandler.java | 6 +- .../api/handlers/JsonRpcObjectExecutor.java | 6 +- .../api/handlers/JsonRpcParserHandler.java | 10 +- .../jsonrpc/JsonRpcEnclaveErrorConverter.java | 10 +- .../api/jsonrpc/JsonRpcErrorConverter.java | 58 ++--- .../AuthenticatedJsonRpcProcessor.java | 4 +- .../execution/BaseJsonRpcProcessor.java | 8 +- .../jsonrpc/execution/JsonRpcExecutor.java | 12 +- .../execution/TracedJsonRpcProcessor.java | 2 +- .../jsonrpc/internal/DebugReplayBlock.java | 4 +- .../methods/AbstractBlockParameterMethod.java | 4 +- ...stractBlockParameterOrBlockHashMethod.java | 14 +- .../internal/methods/AbstractEstimateGas.java | 22 +- .../internal/methods/AdminChangeLogLevel.java | 6 +- .../methods/AdminLogsRemoveCache.java | 4 +- .../internal/methods/AdminModifyPeer.java | 16 +- .../internal/methods/AdminNodeInfo.java | 6 +- .../jsonrpc/internal/methods/AdminPeers.java | 4 +- .../internal/methods/DebugAccountAt.java | 12 +- .../internal/methods/DebugGetRawBlock.java | 4 +- .../internal/methods/DebugGetRawHeader.java | 4 +- .../internal/methods/DebugSetHead.java | 2 +- .../DebugStandardTraceBadBlockToFile.java | 4 +- .../DebugStandardTraceBlockToFile.java | 4 +- .../internal/methods/DebugTraceBlock.java | 6 +- .../api/jsonrpc/internal/methods/EthCall.java | 30 ++- .../jsonrpc/internal/methods/EthCoinbase.java | 4 +- .../internal/methods/EthCreateAccessList.java | 12 +- .../internal/methods/EthEstimateGas.java | 8 +- .../internal/methods/EthFeeHistory.java | 6 +- .../internal/methods/EthGetFilterChanges.java | 4 +- .../internal/methods/EthGetFilterLogs.java | 4 +- .../jsonrpc/internal/methods/EthGetLogs.java | 8 +- .../jsonrpc/internal/methods/EthGetProof.java | 6 +- .../methods/EthGetTransactionByHash.java | 4 +- .../jsonrpc/internal/methods/EthGetWork.java | 4 +- .../internal/methods/EthNewFilter.java | 4 +- .../methods/EthSendRawTransaction.java | 10 +- .../internal/methods/EthSendTransaction.java | 4 +- .../internal/methods/EthSubmitWork.java | 4 +- .../methods/ExecutionEngineJsonRpcMethod.java | 8 +- .../jsonrpc/internal/methods/NetEnode.java | 6 +- .../internal/methods/NetPeerCount.java | 4 +- .../internal/methods/PluginJsonRpcMethod.java | 10 +- .../methods/PluginsReloadConfiguration.java | 6 +- .../jsonrpc/internal/methods/TraceCall.java | 4 +- .../internal/methods/TraceCallMany.java | 10 +- .../jsonrpc/internal/methods/TraceGet.java | 4 +- .../internal/methods/TraceRawTransaction.java | 8 +- .../jsonrpc/internal/methods/Web3Sha3.java | 8 +- .../AbstractEngineForkchoiceUpdated.java | 8 +- .../engine/AbstractEngineGetPayload.java | 4 +- .../engine/AbstractEngineNewPayload.java | 6 +- .../engine/EngineForkchoiceUpdatedV1.java | 6 +- .../EngineGetPayloadBodiesByHashV1.java | 4 +- .../EngineGetPayloadBodiesByRangeV1.java | 6 +- .../engine/EnginePreparePayloadDebug.java | 4 +- .../miner/MinerChangeTargetGasLimit.java | 6 +- .../methods/miner/MinerSetCoinbase.java | 4 +- .../internal/methods/miner/MinerStart.java | 4 +- .../PermAddAccountsToAllowlist.java | 16 +- .../PermAddNodesToAllowlist.java | 20 +- .../PermGetAccountsAllowlist.java | 4 +- .../permissioning/PermGetNodesAllowlist.java | 6 +- .../PermReloadPermissionsFromFile.java | 6 +- .../PermRemoveAccountsFromAllowlist.java | 16 +- .../PermRemoveNodesFromAllowlist.java | 22 +- .../methods/DisabledPrivacyRpcMethod.java | 4 +- .../MultiTenancyRpcMethodDecorator.java | 6 +- .../privacy/methods/PrivGetFilterChanges.java | 4 +- .../privacy/methods/PrivGetFilterLogs.java | 4 +- .../eea/AbstractEeaSendRawTransaction.java | 6 +- .../eea/JsonRpcErrorResponseException.java | 8 +- ...strictedFlexibleEeaSendRawTransaction.java | 8 +- ...strictedOffchainEeaSendRawTransaction.java | 2 +- .../privacy/methods/priv/PrivCall.java | 11 +- .../methods/priv/PrivDebugGetStateRoot.java | 12 +- .../methods/priv/PrivDeletePrivacyGroup.java | 2 +- .../priv/PrivDistributeRawTransaction.java | 12 +- .../methods/priv/PrivFindPrivacyGroup.java | 2 +- .../priv/PrivGetEeaTransactionCount.java | 8 +- .../privacy/methods/priv/PrivGetLogs.java | 4 +- .../methods/priv/PrivGetTransactionCount.java | 6 +- .../priv/PrivGetTransactionReceipt.java | 4 +- .../privacy/methods/priv/PrivNewFilter.java | 4 +- .../privx/PrivxFindFlexiblePrivacyGroup.java | 2 +- .../internal/response/JsonRpcError.java | 243 +++--------------- .../response/JsonRpcErrorResponse.java | 21 +- .../response/JsonRpcUnauthorizedResponse.java | 21 +- .../internal/response/RpcErrorType.java | 229 +++++++++++++++++ .../api/jsonrpc/ipc/JsonRpcIpcService.java | 18 +- .../websocket/WebSocketMessageHandler.java | 16 +- .../websocket/methods/EthSubscribe.java | 6 +- .../websocket/methods/EthUnsubscribe.java | 8 +- .../websocket/methods/PrivSubscribe.java | 4 +- .../websocket/methods/PrivUnsubscribe.java | 6 +- .../JsonRpcHttpServiceParameterizedTest.java | 3 +- .../JsonRpcHttpServiceRpcApisTest.java | 4 +- .../api/jsonrpc/JsonRpcHttpServiceTest.java | 42 +-- .../MaxBatchSizeJsonRpcHttpServiceTest.java | 4 +- ...st.java => RpcErrorTypeConverterTest.java} | 38 +-- .../internal/methods/AdminAddPeerTest.java | 20 +- .../methods/AdminChangeLogLevelTest.java | 8 +- .../methods/AdminLogsRemoveCacheTest.java | 4 +- .../internal/methods/AdminNodeInfoTest.java | 6 +- .../internal/methods/AdminPeersTest.java | 4 +- .../internal/methods/AdminRemovePeerTest.java | 20 +- .../internal/methods/DebugAccountAtTest.java | 26 +- .../internal/methods/DebugTraceBlockTest.java | 4 +- .../jsonrpc/internal/methods/EthCallTest.java | 4 +- .../internal/methods/EthCoinbaseTest.java | 4 +- .../methods/EthCreateAccessListTest.java | 6 +- .../internal/methods/EthEstimateGasTest.java | 17 +- .../internal/methods/EthFeeHistoryTest.java | 14 +- .../methods/EthGetBlockByNumberTest.java | 6 +- .../methods/EthGetFilterChangesTest.java | 4 +- .../methods/EthGetFilterLogsTest.java | 4 +- .../internal/methods/EthGetLogsTest.java | 4 +- .../internal/methods/EthGetProofTest.java | 6 +- .../methods/EthGetTransactionByHashTest.java | 4 +- .../internal/methods/EthGetWorkTest.java | 4 +- .../internal/methods/EthNewFilterTest.java | 4 +- .../methods/EthSendRawTransactionTest.java | 30 +-- .../methods/EthSendTransactionTest.java | 4 +- .../internal/methods/EthSubmitWorkTest.java | 6 +- .../internal/methods/NetEnodeTest.java | 6 +- .../internal/methods/Web3Sha3Test.java | 14 +- .../AbstractEngineForkchoiceUpdatedTest.java | 12 +- .../engine/AbstractEngineNewPayloadTest.java | 2 +- .../engine/EngineForkchoiceUpdatedV1Test.java | 6 +- .../EngineGetPayloadBodiesByHashV1Test.java | 8 +- .../EngineGetPayloadBodiesByRangeV1Test.java | 4 +- .../miner/MinerChangeTargetGasLimitTest.java | 6 +- .../methods/miner/MinerSetCoinbaseTest.java | 4 +- .../methods/miner/MinerStartTest.java | 4 +- .../PermAddAccountsToAllowlistTest.java | 10 +- .../PermAddAccountsToWhitelistTest.java | 10 +- .../PermAddNodesToAllowlistTest.java | 14 +- .../PermAddNodesToWhitelistTest.java | 14 +- .../PermGetNodesAllowlistTest.java | 4 +- .../PermGetNodesWhitelistTest.java | 4 +- .../PermReloadPermissionsFromFileTest.java | 6 +- .../PermRemoveAccountsFromAllowlistTest.java | 10 +- .../PermRemoveAccountsFromWhitelistTest.java | 10 +- .../PermRemoveNodesFromAllowlistTest.java | 14 +- .../PermRemoveNodesFromWhitelistTest.java | 14 +- .../MultiTenancyRpcMethodDecoratorTest.java | 6 +- .../eea/EeaSendRawTransactionTest.java | 26 +- ...ctedFlexibleEeaSendRawTransactionTest.java | 12 +- ...ctedOffchainEeaSendRawTransactionTest.java | 6 +- .../priv/PrivCreatePrivacyGroupTest.java | 6 +- .../priv/PrivDebugGetStateRootTest.java | 4 +- .../priv/PrivDeletePrivacyGroupTest.java | 6 +- .../PrivDistributeRawTransactionTest.java | 4 +- .../priv/PrivFindPrivacyGroupTest.java | 6 +- .../priv/PrivGetEeaTransactionCountTest.java | 14 +- .../priv/PrivGetFilterChangesTest.java | 4 +- .../methods/priv/PrivGetFilterLogsTest.java | 4 +- .../privacy/methods/priv/PrivGetLogsTest.java | 4 +- .../priv/PrivGetPrivateTransactionTest.java | 4 +- .../priv/PrivGetTransactionCountTest.java | 6 +- .../methods/priv/PrivNewFilterTest.java | 4 +- .../PrivxFindFlexiblePrivacyGroupTest.java | 6 +- .../PrivacyApiGroupJsonRpcMethodsTest.java | 4 +- .../WebSocketMessageHandlerTest.java | 14 +- .../websocket/methods/EthSubscribeTest.java | 6 +- .../websocket/methods/EthUnsubscribeTest.java | 8 +- .../websocket/methods/PrivSubscribeTest.java | 4 +- .../methods/PrivUnsubscribeTest.java | 6 +- .../retesteth/methods/TestImportRawBlock.java | 6 +- .../retesteth/methods/TestSetChainParams.java | 4 +- .../methods/TestImportRawBlockTest.java | 10 +- 198 files changed, 1073 insertions(+), 970 deletions(-) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java rename ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/{JsonRpcErrorConverterTest.java => RpcErrorTypeConverterTest.java} (64%) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4659f4d00..ac3eceb02cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - 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) ### 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) 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/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/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/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/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/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/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/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/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/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/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java index 3347b6f93eb..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 @@ -32,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; @@ -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 9a78e361dde..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 @@ -32,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; @@ -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/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..e1a655657fa 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; @@ -85,7 +85,7 @@ 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; }; } @@ -97,7 +97,7 @@ private static ObjectWriter createObjectWriter() { .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/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..516b6aa1c07 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; + return RpcErrorType.LOWER_NONCE_INVALID_TRANSACTION_EXISTS; case TOTAL_DATA_GAS_TOO_HIGH: - return JsonRpcError.TOTAL_DATA_GAS_TOO_HIGH; + return RpcErrorType.TOTAL_DATA_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/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/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/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 3a58d15bec0..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,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.api.jsonrpc.internal.results.TransactionCompleteResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPendingResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; @@ -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 = 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/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/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..807b1387a73 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,7 +22,7 @@ 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.Hash; @@ -34,10 +34,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; 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.EnginePayloadStatusResult; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -261,7 +261,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; } 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/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/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 10d57b929ee..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,7 +16,7 @@ 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; @@ -25,10 +25,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.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; @@ -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/response/JsonRpcError.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java index 9554f6020fc..6c26e8837f0 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,6 +14,8 @@ */ 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; @@ -22,214 +24,27 @@ @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; - 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); + } + + public JsonRpcError(final RpcErrorType errorType) { + this(errorType, null); } @JsonGetter("code") @@ -247,20 +62,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, that.message) + && 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, 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..d2e7fe668e0 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,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; @@ -26,10 +27,16 @@ public class JsonRpcErrorResponse implements JsonRpcResponse { private final Object id; private final JsonRpcError error; + @JsonIgnore private final RpcErrorType errorType; 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)); } @JsonGetter("id") @@ -57,7 +64,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 +76,16 @@ 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 && e.getMessage().equals(message)) + .findFirst() + .get(); + } } 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..78017deca09 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java @@ -0,0 +1,229 @@ +/* + * 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_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"); + + 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/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/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/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..060c9be45ef 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; @@ -62,7 +63,7 @@ public void invalidJsonShouldReturnParseError() 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 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..6954480a088 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; @@ -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/MaxBatchSizeJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/MaxBatchSizeJsonRpcHttpServiceTest.java index d648baaa949..72a00b69649 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,7 +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 io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -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 64% 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..33f6482a5e5 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,7 +16,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 org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import java.util.Arrays; @@ -29,50 +29,50 @@ import org.junit.runners.Parameterized.Parameters; @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 } }); } @@ -81,7 +81,7 @@ public static Collection expectedErrorMapping() { public TransactionInvalidReason txInvalidReason; @Parameter(1) - public JsonRpcError expectedJsonRpcError; + public RpcErrorType expectedJsonRpcError; @Test public void expectedTransactionValidationToJsonRpcErrorConversion() { 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..77bb8100c96 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,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.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; @@ -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..5b9f3e8adda 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,10 +18,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.util.LogConfigurator; import org.apache.logging.log4j.Level; @@ -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/AdminLogsRemoveCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminLogsRemoveCacheTest.java index 788d3126288..45b3ef04ca1 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; @@ -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/AdminNodeInfoTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminNodeInfoTest.java index b87bf4df4fc..01897260fe3 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; @@ -334,7 +334,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 +349,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..86a177f046f 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; @@ -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..2680dabc3e1 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,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.network.exceptions.P2PDisabledException; import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; @@ -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/DebugTraceBlockTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceBlockTest.java index df337f44f2f..8a6503b9205 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; @@ -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/EthCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java index 5bdda906415..b8f967d8616 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,8 @@ 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; 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..3b4f6a53259 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,10 +22,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 org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import java.util.Optional; @@ -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..3387362a314 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; @@ -143,7 +144,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 +157,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..5d8579d468f 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; @@ -97,7 +98,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 +116,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() @@ -179,7 +180,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 +194,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 +209,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 +223,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 +238,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,7 +252,7 @@ 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() 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..18f2b006a50 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; @@ -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/EthGetBlockByNumberTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockByNumberTest.java index b766b093161..2f9683de4fc 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; @@ -139,7 +139,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 +147,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..6370d2c71ce 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; @@ -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..be37626d920 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; @@ -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..31e4b07bcd1 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,10 +31,10 @@ 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; @@ -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/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/EthGetTransactionByHashTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionByHashTest.java index bf065c27bc4..a636fc6913a 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 @@ -24,10 +24,10 @@ 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; @@ -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); 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..73a31a3f587 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; @@ -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/EthNewFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthNewFilterTest.java index 2102add6c72..e734f9d80ca 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; @@ -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/EthSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSendRawTransactionTest.java index 33521b25446..6f26a25525d 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,10 +21,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.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; @@ -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..ebb6a7da631 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,9 +18,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.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.junit.Before; import org.junit.Test; @@ -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..177398a8df8 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; @@ -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/NetEnodeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/NetEnodeTest.java index 826f4aac23c..6ad463a8f61 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; @@ -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/Web3Sha3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/Web3Sha3Test.java index 72417114600..7c1edea8b59 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,10 +18,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.junit.Test; @@ -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..fc02ea467f6 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; @@ -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/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index e8fb1409e4d..175bf718257 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 @@ -21,7 +21,7 @@ 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.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; 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..1d3dc715de7 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,7 +23,7 @@ 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; @@ -71,7 +71,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/EngineGetPayloadBodiesByHashV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java index 8f202199681..bebbc778458 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; @@ -260,11 +260,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..b045f276e00 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; 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..8e160d275f3 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,8 +20,8 @@ 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; @@ -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..97862fe3383 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,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.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; @@ -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/MinerStartTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/miner/MinerStartTest.java index eb09f5f6666..75d0a3a3aa4 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,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.blockcreation.CoinbaseNotSetException; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; @@ -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/permissioning/PermAddAccountsToAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermAddAccountsToAllowlistTest.java index 2eb4cb038b5..719392b4ca8 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; @@ -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..132f9f8fbed 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; @@ -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..4955472cc3c 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; @@ -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..ed620b48016 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; @@ -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/PermGetNodesAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/permissioning/PermGetNodesAllowlistTest.java index 38b6c12cfbb..e7f7e1a297b 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; @@ -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..f7dbd8d2078 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; @@ -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..ed85af348d2 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,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.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; @@ -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..c48ea3bf88b 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; @@ -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..36e73447a82 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; @@ -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..6191f21531a 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; @@ -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..118ec77df58 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; @@ -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/privacy/methods/MultiTenancyRpcMethodDecoratorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/MultiTenancyRpcMethodDecoratorTest.java index 2b1bc68e3f6..81a0c5794f5 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,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.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; @@ -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/eea/EeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java index 4ad29c1931c..d9648e11ca3 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,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.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; @@ -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/RestrictedFlexibleEeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/RestrictedFlexibleEeaSendRawTransactionTest.java index 7d11084308e..0f1c5ed1ae9 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,10 +21,10 @@ 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; @@ -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..27449fa8347 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,10 +22,10 @@ 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; @@ -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/PrivCreatePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java index 3b565f9f045..88c82a4ed48 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; @@ -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..bb4c09711a0 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; 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..be9373fa2ad 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,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.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; @@ -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..8c7bdc6fe05 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; @@ -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..67154d9b7cf 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; @@ -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/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..a15122e842c 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; @@ -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..5ff50aed80a 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; @@ -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..485e27e0099 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; @@ -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/PrivGetPrivateTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java index 580a3388dad..ba1adf4b491 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; @@ -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/PrivNewFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivNewFilterTest.java index dad2bdd3247..bfcf90b93a0 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; @@ -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/privx/PrivxFindFlexiblePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindFlexiblePrivacyGroupTest.java index 8dacbaabdd1..e59cf44ed70 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; @@ -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/methods/PrivacyApiGroupJsonRpcMethodsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java index c546cbf6d57..20c726cc119 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; @@ -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/websocket/WebSocketMessageHandlerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketMessageHandlerTest.java index 5cfa997e465..551281e8749 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; @@ -166,7 +166,7 @@ public void handlerBatchRequestContainingErrorsShouldRespondWithBatchErrors( 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)); @@ -190,7 +190,7 @@ public void jsonDecodeFailureShouldRespondInvalidRequest(final TestContext conte final Async async = context.async(); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_REQUEST); when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); @@ -209,7 +209,7 @@ public void objectMapperFailureShouldRespondInvalidRequest(final TestContext con final Async async = context.async(); final JsonRpcErrorResponse expectedResponse = - new JsonRpcErrorResponse(null, JsonRpcError.INVALID_REQUEST); + new JsonRpcErrorResponse(null, RpcErrorType.INVALID_REQUEST); when(websocketMock.writeFrame(argThat(this::isFinalFrame))).then(completeOnLastFrame(async)); @@ -230,7 +230,7 @@ public void absentMethodShouldRespondMethodNotFound(final TestContext context) { 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)); @@ -254,7 +254,7 @@ 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)); @@ -276,7 +276,7 @@ public void onExceptionProcessingRequestShouldRespondInternalError(final TestCon 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)); 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..09127be7084 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; @@ -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/EthUnsubscribeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/methods/EthUnsubscribeTest.java index a32985ee472..b20af5ad3c6 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; @@ -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..12ffda3bae7 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; @@ -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..5c7e4602c00 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; @@ -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/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/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..93559791ad1 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; @@ -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 From ef020865eb2c78c5c0e8a0a68c64cb16d6e1bf84 Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Mon, 24 Jul 2023 23:16:03 +0530 Subject: [PATCH 14/51] Removed GoQuorum permissioning interop (#5607) * removed quorum permissioning * removed isQuorum Signed-off-by: Nischal Sharma --------- Signed-off-by: Nischal Sharma --- CHANGELOG.md | 9 ++ .../node/configuration/BesuNodeFactory.java | 2 +- .../PermissionedNodeBuilder.java | 2 +- ...PermissioningIbft2StallAcceptanceTest.java | 4 +- .../org/hyperledger/besu/RunnerBuilder.java | 13 +-- .../org/hyperledger/besu/cli/BesuCommand.java | 74 +----------- .../hyperledger/besu/cli/BesuCommandTest.java | 56 +-------- .../besu/config/GenesisConfigOptions.java | 15 --- .../besu/config/JsonGenesisConfigOptions.java | 15 --- .../besu/config/StubGenesisConfigOptions.java | 10 -- .../besu/config/GenesisConfigOptionsTest.java | 17 --- .../valid_config_with_quorum_config.json | 33 ------ .../besu/ethereum/core/Transaction.java | 13 --- .../GoQuorumPermissioningConfiguration.java | 44 ------- .../permissioning/GoQuorumQip714Gate.java | 72 ------------ .../NodePermissioningControllerFactory.java | 17 +-- .../PermissioningConfiguration.java | 11 +- .../AccountPermissioningController.java | 13 +-- ...AccountPermissioningControllerFactory.java | 21 +--- .../node/NodePermissioningController.java | 13 +-- .../permissioning/GoQuorumQip714GateTest.java | 109 ------------------ ...untPermissioningControllerFactoryTest.java | 35 +++--- .../AccountPermissioningControllerTest.java | 51 +------- ...odePermissioningControllerFactoryTest.java | 23 ++-- .../node/NodePermissioningControllerTest.java | 64 +--------- 25 files changed, 56 insertions(+), 680 deletions(-) delete mode 100644 config/src/test/resources/valid_config_with_quorum_config.json delete mode 100644 ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumPermissioningConfiguration.java delete mode 100644 ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714Gate.java delete mode 100644 ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/GoQuorumQip714GateTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ac3eceb02cd..50840e1b872 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Changelog +## 23.7.0 + +### Breaking Changes +- Removed deprecated GoQuorum permissioning interop [#5607](https://github.com/hyperledger/besu/pull/5607) + +### Additions and Improvements + +### Bug Fixes + ## 23.4.5 ### Breaking Changes 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/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/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index d54a9149429..782fb3c46ca 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,13 +1125,12 @@ 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 -> 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 831c52a74f4..182b8f762aa 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -31,7 +31,6 @@ 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 +133,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 +217,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; @@ -1387,8 +1384,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 +1526,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 @@ -2200,8 +2191,6 @@ private void configure() throws Exception { ethNetworkConfig = updateNetworkConfig(network); - checkGoQuorumCompatibilityConfig(ethNetworkConfig); - jsonRpcConfiguration = jsonRpcConfiguration( jsonRPCHttpOptionGroup.rpcHttpPort, jsonRPCHttpOptionGroup.rpcHttpApis, hostsAllowlist); @@ -2811,27 +2800,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; @@ -2854,8 +2827,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(); @@ -2869,10 +2842,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()) @@ -3451,34 +3420,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(); @@ -3532,13 +3473,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( 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 7e634282260..7f78c5d85b3 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -155,13 +155,6 @@ 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 = @@ -4229,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(); @@ -4557,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 @@ -5241,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 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 ba1f52769e8..f60bffec96f 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -466,21 +466,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 ab269142ba2..3c8776cac40 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -400,16 +400,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 +480,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 a0eac55cd8a..0d1648f13d2 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -395,16 +395,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/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java index d04027dcc10..7dcc21a2c7c 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java @@ -266,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/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 bb86c9491a5..3d381ae62b0 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 @@ -735,19 +735,6 @@ public Optional> getVersionedHashes() { return this.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; - } - /** * Return the list of transaction hashes extracted from the collection of Transaction passed as * argument 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 2de2b846657..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 @@ -20,10 +20,8 @@ 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; @@ -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/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/account/AccountPermissioningControllerFactoryTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java index 2c19f3cd37b..85ad5596fe7 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; @@ -44,15 +43,13 @@ 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..5ed0d1e66c7 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,7 +23,6 @@ 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; @@ -41,15 +40,12 @@ public class AccountPermissioningControllerTest { @Mock private AccountLocalConfigPermissioningController localConfigController; @Mock private TransactionSmartContractPermissioningController smartContractController; - @Mock private GoQuorumQip714Gate goQuorumQip714Gate; @Before 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/NodePermissioningControllerFactoryTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/node/NodePermissioningControllerFactoryTest.java index a313c4a60ed..afba9bb18fb 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 @@ -67,7 +67,7 @@ public void before() { @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 +93,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 +121,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 +157,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 +192,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 +230,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 +255,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..512b752895b 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,18 +21,15 @@ 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; @@ -56,7 +53,6 @@ public class NodePermissioningControllerTest { Optional syncStatusNodePermissioningProviderOptional; @Mock private NodeLocalConfigPermissioningController localConfigNodePermissioningProvider; @Mock private NodeConnectionPermissioningProvider otherPermissioningProvider; - @Mock private GoQuorumQip714Gate goQuorumQip714Gate; private NodePermissioningController controller; @@ -66,7 +62,7 @@ public void before() { 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)); - } } From dd129c84acb9fdf58bdee999defef6e8ddcfb9c5 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 24 Jul 2023 13:56:07 -0600 Subject: [PATCH 15/51] Eip 6780 selfdestruct (#5430) * track CREATE/CREATE2/create-tx in a new "creates" field in the MessageFrame * re-wrote Self-Destruct logic for clarity and optional EIP-6780 semantics. Signed-off-by: Danno Ferrin --- .../t8n/cancun-6780-selfdestruct-sweep.json | 114 +++++++++++ .../t8n/cancun-6780-selfdestruct-to-self.json | 113 +++++++++++ .../cancun-6780-selfdestruct-transient.json | 98 +++++++++ .../besu/evmtool/t8n/cancun-blobs-per-tx.json | 1 - .../org/hyperledger/besu/evm/MainnetEVMs.java | 9 +- .../besu/evm/frame/MessageFrame.java | 47 +++++ .../evm/operation/AbstractCallOperation.java | 1 + .../operation/AbstractCreateOperation.java | 2 + .../evm/operation/SelfDestructOperation.java | 65 ++++-- .../processor/ContractCreationProcessor.java | 6 +- .../operations/SelfDestructOperationTest.java | 187 ++++++++++++++++++ 11 files changed, 616 insertions(+), 27 deletions(-) create mode 100644 ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json create mode 100644 ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json create mode 100644 ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json create mode 100644 evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java 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..668434d98ec --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-sweep.json @@ -0,0 +1,114 @@ +{ + "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", + "parentDataGasUsed": "0", + "parentExcessDataGas": "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" + } + } +} \ 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..20314f7f95a --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-to-self.json @@ -0,0 +1,113 @@ +{ + "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", + "parentDataGasUsed": "0", + "parentExcessDataGas": "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" + } + } +} \ 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..5e3c6ea4754 --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-6780-selfdestruct-transient.json @@ -0,0 +1,98 @@ +{ + "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", + "parentDataGasUsed": "0", + "parentExcessDataGas": "0" + } + }, + "stdout": { + "alloc": { + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x48540" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x3635c9adc5de90ee80", + "nonce": "0x1" + } + }, + "body": "0xf873f871800a8405f5e1008080a4600d8060175f39805f80f05f805f805f855af1505ffffe600280600b5f39805ff3fe5fff1ba0f2bb558b73cfb96466c41785fdd0f1e367b4703d49653e617cffdb7316a01e87a011e0423aeea027a1e48dc3adffe2b27652d8154599f10b6f552d51b1fcb632ae", + "result": { + "stateRoot": "0x8d6ff9ecb860b2ca140a73ae8591615e384a4e397d859af831b4a475e47ff7b0", + "txRoot": "0x35ab0ce85af281d6e600d467fb3ed12063994cc9e105cbdb4eb1ba65ed9edddf", + "receiptsRoot": "0x2f9ef11d9889ea86d77151c8a6cf578fed535563e1a016e67997d22984ca1bef", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x181c0", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0xd954e10ebf0b55b71512b53a6ebae09372ccc6b2bf87b199e8aa8a5c4f757430", + "contractAddress": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "gasUsed": "0x181c0", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x181c0", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + } + } +} \ 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 index 8ee3e7b21ad..99acfb9e058 100644 --- 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 @@ -36,7 +36,6 @@ "input": "0x", "to": "0x0000000000000000000000000000000000000100", "accessList": [], - "protected": true, "maxFeePerDataGas": "0x1", "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "blobVersionedHashes": [ 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..4df9415a108 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -843,15 +843,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 DATAHASH + registry.put(new DataHashOperation(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/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java index a71838e22b7..1dd7801ce15 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 @@ -218,6 +218,7 @@ public enum Type { private final List logs; private long gasRefund; private final Set

    selfDestructs; + private final Set
    creates; private final Map refunds; private final Set
    warmedUpAddresses; private final Multimap warmedUpStorage; @@ -305,6 +306,7 @@ private MessageFrame( this.logs = new ArrayList<>(); this.gasRefund = 0L; this.selfDestructs = new HashSet<>(); + this.creates = new HashSet<>(); this.refunds = new HashMap<>(); this.recipient = recipient; this.originator = originator; @@ -971,6 +973,51 @@ public Set
    getSelfDestructs() { return selfDestructs; } + /** + * Add recipient to the create set if not already present. + * + * @param address The recipient to create + */ + public void addCreate(final Address address) { + 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) { + creates.addAll(addresses); + } + + /** Removes all entries in the create set. */ + public void clearCreates() { + creates.clear(); + } + + /** + * Returns the create set. + * + * @return the create set + */ + public Set
    getCreates() { + return 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 creates.contains((address)) + || (parentMessageFrame != null && parentMessageFrame.wasCreatedInTransaction(address)); + } + /** * Add refund to the refunds map if not already present. * 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..5cd11e55a3a 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 @@ -259,6 +259,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(); 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 f3d04f772e7..9496624334a 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 @@ -141,6 +141,7 @@ private void spawnChildMessage(final MessageFrame frame, final Code code, final final Wei value = Wei.wrap(frame.getStackItem(0)); final Address contractAddress = targetContractAddress(frame); + frame.addCreate(contractAddress); final long childGasStipend = gasCalculator().gasAvailableForChildCreate(frame.getRemainingGas()); @@ -184,6 +185,7 @@ 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) { 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/processor/ContractCreationProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java index 58f809aee64..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"); 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..3ed4d38a339 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java @@ -0,0 +1,187 @@ +/* + * 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 java.util.ArrayDeque; + +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)) + .depth(1) + .completer(__ -> {}) + .address(originatorAddress) + .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) + .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); + } + } +} From a57aa1b81da5db7f03241f6648b663d82394df49 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Mon, 24 Jul 2023 17:11:06 -0700 Subject: [PATCH 16/51] 23.7.0 release (#5722) Signed-off-by: garyschulte --- CHANGELOG.md | 19 ++++++++----------- gradle.properties | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50840e1b872..93ddb9157ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,7 @@ ### Breaking Changes - Removed deprecated GoQuorum permissioning interop [#5607](https://github.com/hyperledger/besu/pull/5607) - -### Additions and Improvements - -### Bug Fixes - -## 23.4.5 - -### Breaking Changes - -- Removed support for version 0 of the database as it is no longer used by any active node. +- 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) @@ -23,16 +14,22 @@ - 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: +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.0/besu-23.7.0.zip / sha256: ---- ## 23.4.4 diff --git a/gradle.properties b/gradle.properties index 4d06c3c3ce4..8596c9e0574 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.4.5-SNAPSHOT +version=23.7.0 org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396) From 1a7635bc3ef75c31e5c5ac050b2cd3a22d833ada Mon Sep 17 00:00:00 2001 From: garyschulte Date: Mon, 24 Jul 2023 18:17:41 -0700 Subject: [PATCH 17/51] Prepare for version 23.7.1-SNAPSHOT (#5723) Signed-off-by: garyschulte --- CHANGELOG.md | 16 +++++++++++++--- gradle.properties | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ddb9157ce..e95780060b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ - # Changelog +## 23.7.1 + +### Breaking Changes + +### Additions and Improvements + +### Bug Fixes + +### Download Links + + ## 23.7.0 ### Breaking Changes @@ -27,8 +37,8 @@ - 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: -https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.7.0/besu-23.7.0.zip / sha256: +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/gradle.properties b/gradle.properties index 8596c9e0574..76c31095547 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=23.7.0 +version=23.7.1-SNAPSHOT org.gradle.welcome=never # Set exports/opens flags required by Google Java Format and ErrorProne plugins. (JEP-396) From 6603ebb7169b6096b17a743c4c37bd3ab250a030 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 25 Jul 2023 12:17:24 +0200 Subject: [PATCH 18/51] Introduce transaction validator interface (phase 2) (#5682) Signed-off-by: Fabio Di Fabio --- .../org/hyperledger/besu/RunnerBuilder.java | 2 +- .../besu/services/BesuEventsImplTest.java | 15 +- .../merge/TransitionProtocolSchedule.java | 6 +- .../mainnet/ClassicProtocolSpecs.java | 6 +- .../mainnet/DefaultProtocolSchedule.java | 5 +- .../mainnet/MainnetProtocolSpecs.java | 22 +-- .../mainnet/MainnetTransactionProcessor.java | 11 +- .../mainnet/MainnetTransactionValidator.java | 59 ------- .../PermissionTransactionValidator.java | 75 ++++++++ .../PrivacySupportingProtocolSchedule.java | 3 +- .../besu/ethereum/mainnet/ProtocolSpec.java | 16 +- .../ethereum/mainnet/ProtocolSpecBuilder.java | 33 ++-- .../mainnet/TransactionValidator.java | 10 -- .../mainnet/TransactionValidatorFactory.java | 109 ++++++++++++ .../privacy/PrivateTransactionProcessor.java | 8 +- .../MainnetTransactionProcessorTest.java | 20 ++- .../MainnetTransactionValidatorTest.java | 165 ++++++------------ .../PermissionTransactionValidatorTest.java | 161 +++++++++++++++++ .../eth/transactions/TransactionPool.java | 3 +- .../AbstractTransactionPoolTest.java | 47 +++-- ...actionsLayeredPendingTransactionsTest.java | 45 +++-- .../besu/ethereum/core/TransactionTest.java | 2 +- .../NoRewardProtocolScheduleWrapper.java | 7 +- 23 files changed, 544 insertions(+), 286 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidatorFactory.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidatorTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 782fb3c46ca..857fd4e093e 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -1136,7 +1136,7 @@ private Optional buildAccountPermissioningContro permissioningController -> besuController .getProtocolSchedule() - .setTransactionFilter(permissioningController::isPermitted)); + .setPermissionTransactionFilter(permissioningController::isPermitted)); return accountPermissioningController; } else { 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 75c9b1286e1..dec24832a69 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -51,7 +51,7 @@ 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.TransactionValidator; +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; @@ -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 TransactionValidator 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)); 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 0b2a2f5a372..82fdd8e3438 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 @@ -219,9 +219,11 @@ public String listMilestones() { * @param permissionTransactionFilter the transaction filter */ @Override - public void setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter) { + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { transitionUtils.dispatchConsumerAccordingToMergeState( - protocolSchedule -> protocolSchedule.setTransactionFilter(permissionTransactionFilter)); + protocolSchedule -> + protocolSchedule.setPermissionTransactionFilter(permissionTransactionFilter)); } /** 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 6755d5f6bf7..f217e73e7dd 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 @@ -76,7 +76,7 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( .gasCalculator(TangerineWhistleGasCalculator::new) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator(gasCalculator, gasLimitCalculator, true, chainId)) + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .name("ClassicTangerineWhistle"); } @@ -130,7 +130,7 @@ public static ProtocolSpecBuilder defuseDifficultyBombDefinition( .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator(gasCalculator, gasLimitCalculator, true, chainId)) + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .name("DefuseDifficultyBomb"); } @@ -293,7 +293,7 @@ public static ProtocolSpecBuilder magnetoDefinition( .gasCalculator(BerlinGasCalculator::new) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + 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 b2cdc9ac06c..1a1008cea8f 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 @@ -111,11 +111,12 @@ public boolean anyMatch(final Predicate predicate) { } @Override - public void setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter) { + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { protocolSpecs.forEach( spec -> spec.spec() - .getTransactionValidator() + .getTransactionValidatorFactory() .setPermissionTransactionFilter(permissionTransactionFilter)); } 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 1e94b9e04c2..9a999654cad 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 @@ -124,16 +124,16 @@ public static ProtocolSpecBuilder frontierDefinition( 0)) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, false, Optional.empty())) .transactionProcessorBuilder( (gasCalculator, - transactionValidator, + 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, @@ -199,7 +199,7 @@ public static ProtocolSpecBuilder homesteadDefinition( 0)) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, true, Optional.empty())) .difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD) .name("Homestead"); @@ -277,7 +277,7 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator(gasCalculator, gasLimitCalculator, true, chainId)) + new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .transactionProcessorBuilder( (gasCalculator, transactionValidator, @@ -412,7 +412,7 @@ static ProtocolSpecBuilder berlinDefinition( .gasCalculator(BerlinGasCalculator::new) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, true, @@ -452,7 +452,7 @@ static ProtocolSpecBuilder londonDefinition( new LondonTargetingGasLimitCalculator(londonForkBlockNumber, londonFeeMarket)) .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, londonFeeMarket, @@ -613,7 +613,7 @@ static ProtocolSpecBuilder shanghaiDefinition( // Contract creation rules for EIP-3860 Limit and meter intitcode .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, londonFeeMarket, @@ -696,7 +696,7 @@ static ProtocolSpecBuilder cancunDefinition( // change to check for max data gas per block for EIP-4844 .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> - new MainnetTransactionValidator( + new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, cancunFeeMarket, 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 407c6850daf..b57cf266f81 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 @@ -64,7 +64,7 @@ public class MainnetTransactionProcessor { protected final GasCalculator gasCalculator; - protected final TransactionValidator transactionValidator; + protected final TransactionValidatorFactory transactionValidatorFactory; private final AbstractMessageProcessor contractCreationProcessor; @@ -81,7 +81,7 @@ public class MainnetTransactionProcessor { public MainnetTransactionProcessor( final GasCalculator gasCalculator, - final TransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final boolean clearEmptyAccounts, @@ -90,7 +90,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; @@ -271,6 +271,7 @@ public TransactionProcessingResult processTransaction( final PrivateMetadataUpdater privateMetadataUpdater, final Wei dataGasPrice) { try { + final var transactionValidator = transactionValidatorFactory.get(); LOG.trace("Starting execution of {}", transaction); ValidationResult validationResult = transactionValidator.validate( @@ -498,10 +499,6 @@ public TransactionProcessingResult processTransaction( } } - public TransactionValidator getTransactionValidator() { - return transactionValidator; - } - protected void process(final MessageFrame frame, final OperationTracer operationTracer) { final AbstractMessageProcessor executor = getMessageProcessor(frame.getType()); 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 28ad446e9c1..777a68ba948 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 @@ -22,7 +22,6 @@ import org.hyperledger.besu.datatypes.TransactionType; 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.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; @@ -49,40 +48,10 @@ public class MainnetTransactionValidator implements TransactionValidator { private final Optional chainId; - private Optional permissionTransactionFilter = 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, @@ -239,12 +208,6 @@ 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(); } @@ -286,26 +249,4 @@ private ValidationResult validateTransactionSignature( } return ValidationResult.valid(); } - - private boolean isSenderAllowed( - final Transaction transaction, final TransactionValidationParams validationParams) { - if (validationParams.checkLocalPermissions() || validationParams.checkOnchainPermissions()) { - return permissionTransactionFilter - .map( - c -> - c.permitted( - transaction, - validationParams.checkLocalPermissions(), - validationParams.checkOnchainPermissions())) - .orElse(true); - } else { - return true; - } - } - - @Override - public void setPermissionTransactionFilter( - final PermissionTransactionFilter permissionTransactionFilter) { - this.permissionTransactionFilter = Optional.of(permissionTransactionFilter); - } } 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 aed9a52f7b9..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 @@ -22,7 +22,8 @@ public interface PrivacySupportingProtocolSchedule { - void setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter); + void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter); void setPublicWorldStateArchiveForPrivacyBlockProcessor( final WorldStateArchive publicWorldStateArchive); 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 8805ad556e0..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 TransactionValidator transactionValidator; + private final TransactionValidatorFactory transactionValidatorFactory; private final MainnetTransactionProcessor transactionProcessor; @@ -87,7 +87,7 @@ public class ProtocolSpec { * * @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 @@ -118,7 +118,7 @@ public class ProtocolSpec { public ProtocolSpec( final String name, final EVM evm, - final TransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final MainnetTransactionProcessor transactionProcessor, final PrivateTransactionProcessor privateTransactionProcessor, final BlockHeaderValidator blockHeaderValidator, @@ -146,7 +146,7 @@ public ProtocolSpec( final boolean isReplayProtectionSupported) { this.name = name; this.evm = evm; - this.transactionValidator = transactionValidator; + this.transactionValidatorFactory = transactionValidatorFactory; this.transactionProcessor = transactionProcessor; this.privateTransactionProcessor = privateTransactionProcessor; this.blockHeaderValidator = blockHeaderValidator; @@ -184,12 +184,12 @@ 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 TransactionValidator getTransactionValidator() { - return transactionValidator; + public TransactionValidatorFactory getTransactionValidatorFactory() { + return transactionValidatorFactory; } public boolean 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 60787068dbb..697f1112d2b 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 @@ -53,8 +53,8 @@ public class ProtocolSpecBuilder { private DifficultyCalculator difficultyCalculator; private EvmConfiguration evmConfiguration; private BiFunction evmBuilder; - private BiFunction - transactionValidatorBuilder; + private BiFunction + transactionValidatorFactoryBuilder; private Function blockHeaderValidatorBuilder; private Function ommerHeaderValidatorBuilder; private Function blockBodyValidatorBuilder; @@ -126,9 +126,9 @@ public ProtocolSpecBuilder evmBuilder( } public ProtocolSpecBuilder transactionValidatorBuilder( - final BiFunction - transactionValidatorBuilder) { - this.transactionValidatorBuilder = transactionValidatorBuilder; + final BiFunction + transactionValidatorFactoryBuilder) { + this.transactionValidatorFactoryBuilder = transactionValidatorFactoryBuilder; return this; } @@ -282,7 +282,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator"); 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"); @@ -309,8 +309,8 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { final EVM evm = evmBuilder.apply(gasCalculator, evmConfiguration); final PrecompiledContractConfiguration precompiledContractConfiguration = new PrecompiledContractConfiguration(gasCalculator, privacyParameters); - final TransactionValidator transactionValidator = - transactionValidatorBuilder.apply(gasCalculator, gasLimitCalculator); + final TransactionValidatorFactory transactionValidatorFactory = + transactionValidatorFactoryBuilder.apply(gasCalculator, gasLimitCalculator); final AbstractMessageProcessor contractCreationProcessor = contractCreationProcessorBuilder.apply(gasCalculator, evm); final PrecompileContractRegistry precompileContractRegistry = @@ -319,7 +319,10 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { messageCallProcessorBuilder.apply(evm, precompileContractRegistry); final MainnetTransactionProcessor transactionProcessor = transactionProcessorBuilder.apply( - gasCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor); + gasCalculator, + transactionValidatorFactory, + contractCreationProcessor, + messageCallProcessor); final BlockHeaderValidator blockHeaderValidator = createBlockHeaderValidator(blockHeaderValidatorBuilder); @@ -333,7 +336,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { // Set private Tx Processor PrivateTransactionProcessor privateTransactionProcessor = createPrivateTransactionProcessor( - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, precompileContractRegistry); @@ -357,7 +360,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { return new ProtocolSpec( name, evm, - transactionValidator, + transactionValidatorFactory, transactionProcessor, privateTransactionProcessor, blockHeaderValidator, @@ -386,7 +389,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { } private PrivateTransactionProcessor createPrivateTransactionProcessor( - final TransactionValidator transactionValidator, + final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, final PrecompileContractRegistry precompileContractRegistry) { @@ -396,7 +399,7 @@ private PrivateTransactionProcessor createPrivateTransactionProcessor( privateTransactionValidatorBuilder.apply(); privateTransactionProcessor = privateTransactionProcessorBuilder.apply( - transactionValidator, + transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, privateTransactionValidator); @@ -443,14 +446,14 @@ private BlockHeaderValidator createBlockHeaderValidator( public interface TransactionProcessorBuilder { MainnetTransactionProcessor apply( GasCalculator gasCalculator, - TransactionValidator transactionValidator, + TransactionValidatorFactory transactionValidatorFactory, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor); } public interface PrivateTransactionProcessorBuilder { PrivateTransactionProcessor apply( - TransactionValidator transactionValidator, + TransactionValidatorFactory transactionValidatorFactory, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor, PrivateTransactionValidator privateTransactionValidator); 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 index 81514f0edde..a70de0bcd7f 100644 --- 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 @@ -15,7 +15,6 @@ 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; @@ -53,13 +52,4 @@ ValidationResult validate( */ ValidationResult validateForSender( Transaction transaction, Account sender, TransactionValidationParams validationParams); - - /** - * Set the permission transaction filter. This way of setting the filter is deprecated and will be - * removed. - * - * @param permissionTransactionFilter the permission transaction filter - */ - @Deprecated - void setPermissionTransactionFilter(PermissionTransactionFilter permissionTransactionFilter); } 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..f21be83d0e1 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidatorFactory.java @@ -0,0 +1,109 @@ +/* + * 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.Suppliers; + +public class TransactionValidatorFactory { + private final GasCalculator gasCalculator; + private final GasLimitCalculator gasLimitCalculator; + private final FeeMarket feeMarket; + private final boolean disallowSignatureMalleability; + private final Optional chainId; + private final Set acceptedTransactionTypes; + private final int maxInitcodeSize; + private Optional permissionTransactionFilter = Optional.empty(); + + 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.gasCalculator = gasCalculator; + this.gasLimitCalculator = gasLimitCalculator; + this.feeMarket = feeMarket; + this.disallowSignatureMalleability = checkSignatureMalleability; + this.chainId = chainId; + this.acceptedTransactionTypes = acceptedTransactionTypes; + this.maxInitcodeSize = maxInitcodeSize; + } + + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { + this.permissionTransactionFilter = Optional.of(permissionTransactionFilter); + } + + public TransactionValidator get() { + return Suppliers.memoize(this::createTransactionValidator).get(); + } + + private TransactionValidator createTransactionValidator() { + final TransactionValidator baseValidator = + new MainnetTransactionValidator( + gasCalculator, + gasLimitCalculator, + feeMarket, + disallowSignatureMalleability, + chainId, + acceptedTransactionTypes, + maxInitcodeSize); + if (permissionTransactionFilter.isPresent()) { + return new PermissionTransactionValidator(baseValidator, permissionTransactionFilter.get()); + } + return baseValidator; + } +} 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 fdbeb19bf70..8cd8db2bf49 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.TransactionValidator; +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; @@ -49,7 +49,7 @@ public class PrivateTransactionProcessor { private static final Logger LOG = LoggerFactory.getLogger(PrivateTransactionProcessor.class); @SuppressWarnings("unused") - private final TransactionValidator transactionValidator; + private final TransactionValidatorFactory transactionValidatorFactory; private final PrivateTransactionValidator privateTransactionValidator; @@ -63,13 +63,13 @@ public class PrivateTransactionProcessor { private final boolean clearEmptyAccounts; public PrivateTransactionProcessor( - final TransactionValidator 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; 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 508448bc4ab..ff0bca70520 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 @@ -43,6 +43,7 @@ import org.apache.tuweni.bytes.Bytes; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -53,7 +54,10 @@ public class MainnetTransactionProcessorTest { private static final int MAX_STACK_SIZE = 1024; private final GasCalculator gasCalculator = new LondonGasCalculator(); - @Mock private TransactionValidator 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 34fc7f1d804..2475d618132 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 @@ -24,7 +24,6 @@ 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; @@ -36,7 +35,6 @@ import org.hyperledger.besu.datatypes.TransactionType; 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.mainnet.feemarket.FeeMarket; @@ -53,7 +51,6 @@ import org.apache.tuweni.bytes.Bytes; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -74,10 +71,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 TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); final Transaction transaction = new TransactionTestFixture() @@ -94,7 +124,7 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { @Test public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) .isEqualTo( @@ -105,7 +135,7 @@ public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot( @Test public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, @@ -117,7 +147,7 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { @Test public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); assertThat(validator.validateForSender(basicTransaction, null, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE)); @@ -126,7 +156,7 @@ public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { @Test public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() + 1); @@ -138,7 +168,7 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { public void shouldRejectTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsNotAllowed() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); @@ -150,7 +180,7 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { public void shouldAcceptTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsAllowed() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); @@ -161,7 +191,7 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { @Test public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final Transaction transaction = @@ -175,7 +205,7 @@ public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { @Test public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.of(BigInteger.ONE)); final TransactionTestFixture builder = new TransactionTestFixture(); @@ -192,9 +222,8 @@ public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { @Test public void shouldRejectTransactionIfAccountIsNotEOA() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setPermissionTransactionFilter(transactionFilter(false)); Account invalidEOA = when(account(basicTransaction.getUpfrontCost(0L), basicTransaction.getNonce()) @@ -202,42 +231,15 @@ public void shouldRejectTransactionIfAccountIsNotEOA() { .thenReturn(Hash.fromHexStringLenient("0xdeadbeef")) .getMock(); - assertThat(validator.validateForSender(basicTransaction, invalidEOA, transactionPoolParams)) - .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); - } - - @Test - public void shouldRejectTransactionIfAccountIsNotPermitted() { - final TransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setPermissionTransactionFilter(transactionFilter(false)); - - assertThat( - validator.validateForSender( - basicTransaction, accountWithNonce(0), transactionPoolParams)) + assertThat(validator.validateForSender(basicTransaction, invalidEOA, processingBlockParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED)); } - @Test - public void shouldAcceptValidTransactionIfAccountIsPermitted() { - final TransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setPermissionTransactionFilter(transactionFilter(true)); - - assertThat( - validator.validateForSender( - basicTransaction, accountWithNonce(0), transactionPoolParams)) - .isEqualTo(ValidationResult.valid()); - } - @Test public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setPermissionTransactionFilter(transactionFilter(true)); assertThat( validator.validateForSender( @@ -260,7 +262,7 @@ public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { @Test public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -271,7 +273,6 @@ public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559 }), Integer.MAX_VALUE); - validator.setPermissionTransactionFilter(transactionFilter(true)); final Transaction transaction = Transaction.builder() @@ -294,62 +295,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 PermissionTransactionFilter permissionTransactionFilter = - mock(PermissionTransactionFilter.class); - when(permissionTransactionFilter.permitted( - any(Transaction.class), - stateChangeLocalParamCaptor.capture(), - stateChangeOnchainParamCaptor.capture())) - .thenReturn(true); - - final TransactionValidator validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setPermissionTransactionFilter(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 validator = - new MainnetTransactionValidator( - gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - validator.setPermissionTransactionFilter(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); - } - @Test public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { final TransactionValidator frontierValidator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.legacy(), @@ -392,7 +341,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { @Test public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -416,7 +365,7 @@ public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { final Optional zeroBaseFee = Optional.of(Wei.ZERO); final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L, zeroBaseFee), @@ -439,7 +388,7 @@ public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { @Test public void shouldAcceptValidEIP1559() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -464,7 +413,7 @@ public void shouldAcceptValidEIP1559() { @Test public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransactionPool() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -490,7 +439,7 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction @Test public void shouldRejectTooLargeInitcode() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -517,7 +466,7 @@ public void shouldRejectTooLargeInitcode() { @Test public void shouldAcceptTransactionWithAtLeastOneBlob() { final TransactionValidator validator = - new MainnetTransactionValidator( + createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), FeeMarket.london(0L), @@ -547,12 +496,4 @@ private Account account(final Wei balance, final long nonce) { 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/PermissionTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidatorTest.java new file mode 100644 index 00000000000..e25a31ad8be --- /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.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.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/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 18eaf4cf6c3..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 @@ -364,7 +364,8 @@ private static void logReAddedTransactions( private TransactionValidator getTransactionValidator() { return protocolSchedule .getByBlockHeader(protocolContext.getBlockchain().getChainHeadHeader()) - .getTransactionValidator(); + .getTransactionValidatorFactory() + .get(); } private ValidationResultAndAccount validateLocalTransaction(final Transaction transaction) { 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 5b4a11f441d..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 @@ -61,7 +61,7 @@ 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.TransactionValidator; +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 TransactionValidator 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 b10b4dcf7c5..25275043432 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 @@ -61,7 +61,7 @@ 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.TransactionValidator; +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; @@ -80,6 +80,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -93,7 +94,10 @@ public abstract class AbstractTransactionsLayeredPendingTransactionsTest { private static final KeyPair KEY_PAIR2 = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - @Mock protected TransactionValidator transactionValidator; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected TransactionValidatorFactory transactionValidatorFactory; + @Mock protected PendingTransactionAddedListener listener; @Mock protected MiningParameters miningParameters; @Mock protected TransactionsMessageSender transactionsMessageSender; @@ -135,7 +139,7 @@ public void setUp() { 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 +366,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 +430,7 @@ public void shouldDiscardRemoteTransactionThatAlreadyExistsBeforeValidation() { transactionPool.addRemoteTransactions(singletonList(transaction0)); verify(transactions).containsTransaction(transaction0); - verifyNoInteractions(transactionValidator); + verifyNoInteractions(transactionValidatorFactory); } @Test @@ -551,9 +558,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 +656,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/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 fd595cfb158..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 @@ -54,7 +54,7 @@ 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/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 a4f27328f9c..ce6ee0391d6 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 @@ -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(), @@ -121,8 +121,9 @@ public String listMilestones() { } @Override - public void setTransactionFilter(final PermissionTransactionFilter permissionTransactionFilter) { - delegate.setTransactionFilter(permissionTransactionFilter); + public void setPermissionTransactionFilter( + final PermissionTransactionFilter permissionTransactionFilter) { + delegate.setPermissionTransactionFilter(permissionTransactionFilter); } @Override From 749a69e83b7811e708b1039ddc628d9e4cd2792f Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Tue, 25 Jul 2023 21:03:46 +0530 Subject: [PATCH 19/51] junit4 removed for ethereum/api (#5713) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/api/build.gradle | 9 +- .../api/graphql/AbstractDataFetcherTest.java | 4 +- .../AbstractEthGraphQLHttpServiceTest.java | 20 +-- .../api/graphql/BlockDataFetcherTest.java | 8 +- .../api/graphql/EthGraphQLHttpBySpecTest.java | 168 +++++++----------- .../api/graphql/GraphQLConfigurationTest.java | 2 +- .../GraphQLHttpServiceHostWhitelistTest.java | 23 +-- .../api/graphql/GraphQLHttpServiceTest.java | 27 ++- .../api/graphql/scalar/AddressScalarTest.java | 6 +- .../api/graphql/scalar/BigIntScalarTest.java | 6 +- .../api/graphql/scalar/Bytes32ScalarTest.java | 6 +- .../api/graphql/scalar/BytesScalarTest.java | 6 +- .../api/graphql/scalar/LongScalarTest.java | 6 +- .../AbstractJsonRpcHttpBySpecTest.java | 18 +- .../AbstractJsonRpcHttpServiceTest.java | 18 +- .../jsonrpc/AdminJsonRpcHttpServiceTest.java | 6 +- .../api/jsonrpc/JsonResponseStreamerTest.java | 15 +- .../api/jsonrpc/JsonRpcConfigurationTest.java | 2 +- .../JsonRpcHttpServiceHostAllowlistTest.java | 21 +-- .../jsonrpc/JsonRpcHttpServiceLoginTest.java | 28 +-- .../JsonRpcHttpServiceParameterizedTest.java | 26 +-- .../api/jsonrpc/JsonRpcHttpServiceTest.java | 10 +- .../jsonrpc/JsonRpcHttpServiceTestBase.java | 16 +- .../JsonRpcHttpServiceTlsClientAuthTest.java | 21 ++- ...RpcHttpServiceTlsMisconfigurationTest.java | 2 +- .../jsonrpc/JsonRpcHttpServiceTlsTest.java | 21 ++- .../api/jsonrpc/LatestNonceProviderTest.java | 12 +- ...imitConnectionsJsonRpcHttpServiceTest.java | 6 +- .../MaxBatchSizeJsonRpcHttpServiceTest.java | 2 +- .../jsonrpc/RpcErrorTypeConverterTest.java | 21 +-- .../AuthenticationServiceTest.java | 2 +- .../AuthenticationUtilsTest.java | 2 +- .../authentication/EngineAuthServiceTest.java | 2 +- .../JWTAuthOptionsFactoryTest.java | 2 +- .../jsonrpc/authentication/TomlAuthTest.java | 70 +++----- .../jsonrpc/authentication/TomlUserTest.java | 2 +- .../bonsai/DebugJsonRpcHttpBySpecTest.java | 13 +- .../EthByzantiumJsonRpcHttpBySpecTest.java | 13 +- .../bonsai/EthJsonRpcHttpBySpecTest.java | 13 +- .../bonsai/TraceJsonRpcHttpBySpecTest.java | 13 +- .../api/jsonrpc/context/ContextKeyTest.java | 24 +-- .../forest/DebugJsonRpcHttpBySpecTest.java | 13 +- .../EthByzantiumJsonRpcHttpBySpecTest.java | 13 +- .../forest/EthJsonRpcHttpBySpecTest.java | 13 +- .../forest/TraceJsonRpcHttpBySpecTest.java | 13 +- .../jsonrpc/health/ReadinessCheckTest.java | 2 +- .../api/jsonrpc/internal/QosTimerTest.java | 55 +++--- .../filter/EthJsonRpcHttpServiceTest.java | 2 +- .../filter/FilterIdGeneratorTest.java | 2 +- .../filter/FilterManagerLogFilterTest.java | 12 +- .../internal/filter/FilterManagerTest.java | 12 +- .../internal/filter/FilterRepositoryTest.java | 6 +- .../jsonrpc/internal/filter/FilterTest.java | 2 +- .../filter/FilterTimeoutMonitorTest.java | 12 +- .../internal/filter/LogsQueryTest.java | 2 +- .../internal/methods/AdminAddPeerTest.java | 12 +- .../methods/AdminChangeLogLevelTest.java | 12 +- .../AdminGenerateLogBloomCacheTest.java | 12 +- .../methods/AdminLogsRemoveCacheTest.java | 12 +- .../methods/AdminLogsRepairCacheTest.java | 12 +- .../internal/methods/AdminNodeInfoTest.java | 15 +- .../internal/methods/AdminPeersTest.java | 12 +- .../internal/methods/AdminRemovePeerTest.java | 12 +- .../DebugBatchSendRawTransactionTest.java | 12 +- .../methods/DebugGetBadBlockTest.java | 2 +- .../internal/methods/DebugMetricsTest.java | 2 +- .../DebugStandardTraceBadBlockToFileTest.java | 14 +- .../DebugStandardTraceBlockToFileTest.java | 11 +- .../methods/DebugStorageRangeAtTest.java | 6 +- .../methods/DebugTraceBlockByHashTest.java | 6 +- .../methods/DebugTraceBlockByNumberTest.java | 2 +- .../internal/methods/DebugTraceBlockTest.java | 2 +- .../methods/DebugTraceTransactionTest.java | 6 +- .../internal/methods/EthBlockNumberTest.java | 12 +- .../jsonrpc/internal/methods/EthCallTest.java | 15 +- .../internal/methods/EthChainIdTest.java | 6 +- .../internal/methods/EthCoinbaseTest.java | 12 +- .../methods/EthCreateAccessListTest.java | 15 +- .../internal/methods/EthEstimateGasTest.java | 15 +- .../internal/methods/EthFeeHistoryTest.java | 6 +- .../internal/methods/EthGasPriceTest.java | 12 +- .../methods/EthGetBlockByHashTest.java | 12 +- .../methods/EthGetBlockByNumberTest.java | 15 +- .../methods/EthGetFilterChangesTest.java | 12 +- .../methods/EthGetFilterLogsTest.java | 12 +- .../internal/methods/EthGetLogsTest.java | 12 +- .../EthGetMinerDataByBlockHashTest.java | 12 +- .../EthGetMinerDataByBlockNumberTest.java | 12 +- ...GetTransactionByBlockHashAndIndexTest.java | 8 +- .../methods/EthGetTransactionByHashTest.java | 12 +- .../methods/EthGetTransactionReceiptTest.java | 2 +- .../EthGetUncleByBlockHashAndIndexTest.java | 12 +- .../EthGetUncleByBlockNumberAndIndexTest.java | 12 +- .../internal/methods/EthGetWorkTest.java | 12 +- .../internal/methods/EthHashrateTest.java | 12 +- .../internal/methods/EthMiningTest.java | 12 +- .../methods/EthNewBlockFilterTest.java | 12 +- .../internal/methods/EthNewFilterTest.java | 12 +- .../methods/EthProtocolVersionTest.java | 2 +- .../methods/EthSendRawTransactionTest.java | 12 +- .../methods/EthSendTransactionTest.java | 6 +- .../internal/methods/EthSubmitWorkTest.java | 12 +- .../internal/methods/EthSyncingTest.java | 12 +- .../internal/methods/NetEnodeTest.java | 12 +- .../internal/methods/NetListeningTest.java | 12 +- .../internal/methods/NetVersionTest.java | 6 +- .../internal/methods/RpcModulesTest.java | 6 +- .../TxPoolBesuPendingTransactionsTest.java | 15 +- .../methods/TxPoolBesuStatisticsTest.java | 12 +- .../methods/TxPoolBesuTransactionsTest.java | 12 +- .../methods/Web3ClientVersionTest.java | 2 +- .../internal/methods/Web3Sha3Test.java | 2 +- .../AbstractEngineForkchoiceUpdatedTest.java | 12 +- .../engine/AbstractEngineGetPayloadTest.java | 12 +- .../engine/AbstractEngineNewPayloadTest.java | 16 +- .../EngineExchangeCapabilitiesTest.java | 12 +- ...neExchangeTransitionConfigurationTest.java | 12 +- .../engine/EngineForkchoiceUpdatedV1Test.java | 11 +- .../engine/EngineForkchoiceUpdatedV2Test.java | 11 +- .../EngineGetPayloadBodiesByHashV1Test.java | 15 +- .../EngineGetPayloadBodiesByRangeV1Test.java | 15 +- .../engine/EngineGetPayloadV1Test.java | 11 +- .../engine/EngineGetPayloadV2Test.java | 11 +- .../engine/EngineNewPayloadV1Test.java | 11 +- .../engine/EngineNewPayloadV2Test.java | 11 +- .../engine/EnginePreparePayloadDebugTest.java | 12 +- .../methods/engine/EngineQosTimerTest.java | 35 ++-- .../miner/MinerChangeTargetGasLimitTest.java | 6 +- .../methods/miner/MinerSetCoinbaseTest.java | 12 +- .../methods/miner/MinerSetEtherbaseTest.java | 12 +- .../methods/miner/MinerStartTest.java | 12 +- .../internal/methods/miner/MinerStopTest.java | 12 +- .../PermAddAccountsToAllowlistTest.java | 12 +- .../PermAddAccountsToWhitelistTest.java | 12 +- .../PermAddNodesToAllowlistTest.java | 12 +- .../PermAddNodesToWhitelistTest.java | 12 +- .../PermGetAccountsAllowlistTest.java | 12 +- .../PermGetAccountsWhitelistTest.java | 12 +- .../PermGetNodesAllowlistTest.java | 12 +- .../PermGetNodesWhitelistTest.java | 12 +- .../PermReloadPermissionsFromFileTest.java | 12 +- .../PermRemoveAccountsFromAllowlistTest.java | 12 +- .../PermRemoveAccountsFromWhitelistTest.java | 12 +- .../PermRemoveNodesFromAllowlistTest.java | 12 +- .../PermRemoveNodesFromWhitelistTest.java | 12 +- .../parameters/BlockParameterTest.java | 2 +- .../parameters/DepositParameterTest.java | 2 +- .../EnginePayloadAttributesParameterTest.java | 2 +- .../parameters/FilterParameterTest.java | 2 +- .../parameters/TraceTypeParameterTest.java | 2 +- .../parameters/WithdrawalParameterTest.java | 2 +- .../MultiTenancyRpcMethodDecoratorTest.java | 8 +- .../methods/MultiTenancyUserUtilTest.java | 2 +- .../eea/EeaSendRawTransactionTest.java | 12 +- .../eea/PluginEeaSendRawTransactionTest.java | 12 +- ...ctedFlexibleEeaSendRawTransactionTest.java | 12 +- ...ctedOffchainEeaSendRawTransactionTest.java | 12 +- .../privacy/methods/priv/PrivCallTest.java | 12 +- .../priv/PrivCreatePrivacyGroupTest.java | 6 +- .../priv/PrivDebugGetStateRootTest.java | 6 +- .../priv/PrivDeletePrivacyGroupTest.java | 6 +- .../PrivDistributeRawTransactionTest.java | 12 +- .../priv/PrivFindPrivacyGroupTest.java | 6 +- .../privacy/methods/priv/PrivGetCodeTest.java | 15 +- .../priv/PrivGetFilterChangesTest.java | 12 +- .../methods/priv/PrivGetFilterLogsTest.java | 12 +- .../privacy/methods/priv/PrivGetLogsTest.java | 12 +- .../PrivGetPrivacyPrecompileAddressTest.java | 2 +- .../priv/PrivGetPrivateTransactionTest.java | 12 +- .../priv/PrivGetTransactionReceiptTest.java | 15 +- .../methods/priv/PrivNewFilterTest.java | 12 +- .../methods/priv/PrivUninstallFilterTest.java | 12 +- .../PrivxFindFlexiblePrivacyGroupTest.java | 6 +- .../processor/TransactionTracerTest.java | 24 +-- .../internal/results/NetworkResultTest.java | 2 +- .../TransactionCompleteResultTest.java | 2 +- .../tracing/flat/FlatTraceGeneratorTest.java | 8 +- .../flat/RewardTraceGeneratorTest.java | 12 +- ...endingPermissionTransactionFilterTest.java | 30 +--- .../methods/PermJsonRpcMethodsTest.java | 12 +- .../methods/PrivJsonRpcMethodsTest.java | 12 +- .../PrivacyApiGroupJsonRpcMethodsTest.java | 12 +- .../methods/PrivxJsonRpcMethodsTest.java | 12 +- .../TraceCallManyParameterTest.java | 6 +- .../jsonrpc/timeout/TimeoutHandlerTest.java | 24 +-- .../websocket/JsonResponseStreamerTest.java | 15 +- .../api/jsonrpc/websocket/JsonRpcJWTTest.java | 65 +++---- .../websocket/WebSocketConfigurationTest.java | 2 +- .../websocket/WebSocketHostAllowlistTest.java | 71 ++++---- .../WebSocketMessageHandlerTest.java | 112 ++++++------ .../websocket/WebSocketServiceLoginTest.java | 99 ++++++----- .../websocket/WebSocketServiceTest.java | 142 ++++++++------- .../methods/EthSubscribeIntegrationTest.java | 44 ++--- .../websocket/methods/EthSubscribeTest.java | 6 +- .../EthUnsubscribeIntegrationTest.java | 41 +++-- .../websocket/methods/EthUnsubscribeTest.java | 6 +- .../websocket/methods/PrivSubscribeTest.java | 12 +- .../methods/PrivUnsubscribeTest.java | 12 +- .../methods/WebSocketMethodsFactoryTest.java | 12 +- .../subscription/SubscriptionBuilderTest.java | 6 +- .../SubscriptionManagerSendMessageTest.java | 57 +++--- .../subscription/SubscriptionManagerTest.java | 6 +- ...ewBlockHeadersSubscriptionServiceTest.java | 12 +- .../logs/LogsSubscriptionServiceTest.java | 12 +- ...sactionDroppedSubscriptionServiceTest.java | 12 +- ...ingTransactionSubscriptionServiceTest.java | 12 +- .../SubscriptionRequestMapperTest.java | 6 +- .../SyncingSubscriptionServiceTest.java | 12 +- .../ethereum/api/query/BackendQueryTest.java | 53 ++---- .../query/BlockchainQueriesLogCacheTest.java | 32 ++-- .../api/query/BlockchainQueriesTest.java | 6 +- .../ethereum/api/query/LogsQueryTest.java | 2 +- .../api/query/PrivacyQueriesTest.java | 15 +- .../api/query/StateBackupServiceTest.java | 2 +- .../cache/TransactionLogBloomCacherTest.java | 54 +++--- .../tls/FileBasedPasswordProviderTest.java | 11 +- .../api/util/DomainObjectDecodeUtilsTest.java | 2 +- 217 files changed, 1511 insertions(+), 1663 deletions(-) diff --git a/ethereum/api/build.gradle b/ethereum/api/build.gradle index 79accd5c5e1..5e526239088 100644 --- a/ethereum/api/build.gradle +++ b/ethereum/api/build.gradle @@ -93,19 +93,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 +110,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/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 285094cc369..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 @@ -38,6 +38,7 @@ import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.testutil.BlockTestUtil; +import java.nio.file.Path; import java.util.Collections; import java.util.HashSet; import java.util.Map; @@ -48,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; @@ -72,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( @@ -80,7 +80,7 @@ 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)); @@ -133,7 +133,7 @@ public void setupTest() throws Exception { service = new GraphQLHttpService( vertx, - folder.newFolder().toPath(), + tempDir, config, graphQL, Map.of( @@ -154,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 8d8e1fc47ae..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 @@ -51,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; @@ -63,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; @@ -115,7 +115,7 @@ protected BlockchainSetupUtil createBlockchainSetupUtil( new ChainResources(genesisURL, blocksURL), storageFormat); } - @Before + @BeforeEach public void setup() throws Exception { setupBlockchain(); } @@ -185,7 +185,7 @@ protected Map getRpcMethods( mock(MetricsConfiguration.class), natService, new HashMap<>(), - folder.getRoot().toPath(), + folder, mock(EthPeers.class), syncVertx, Optional.empty(), @@ -207,7 +207,7 @@ private void startService(final BlockchainSetupUtil blockchainSetupUtil) throws service = new JsonRpcHttpService( vertx, - folder.newFolder().toPath(), + folder, config, new NoOpMetricsSystem(), natService, @@ -220,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 060c9be45ef..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 @@ -25,39 +25,31 @@ 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()) { 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 6954480a088..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 @@ -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(); } 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 57d5e8f13da..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 @@ -23,13 +23,13 @@ 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"); @@ -39,7 +39,7 @@ public class LatestNonceProviderTest { @Mock private TransactionPool transactionPool; - @Before + @BeforeEach public void setUp() { nonceProvider = new LatestNonceProvider(blockchainQueries, transactionPool); } 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 72a00b69649..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 @@ -23,7 +23,7 @@ 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 { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java index 33f6482a5e5..6a52b39c853 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java @@ -22,16 +22,11 @@ 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 RpcErrorTypeConverterTest { - @Parameters public static Collection expectedErrorMapping() { return Arrays.asList( new Object[][] { @@ -77,14 +72,10 @@ public static Collection expectedErrorMapping() { }); } - @Parameter(0) - public TransactionInvalidReason txInvalidReason; - - @Parameter(1) - public RpcErrorType 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/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..d881c866da7 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 { 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 77bb8100c96..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 @@ -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.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( 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 5b9f3e8adda..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 @@ -25,19 +25,19 @@ 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"); 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 45b3ef04ca1..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 @@ -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); } 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 01897260fe3..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 @@ -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); 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 86a177f046f..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 @@ -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); } 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 2680dabc3e1..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 @@ -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.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( 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 8a6503b9205..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 @@ -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; 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 b8f967d8616..b3588a6c46c 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 @@ -52,15 +52,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 +77,7 @@ public class EthCallTest { @Captor ArgumentCaptor>> mapperCaptor; - @Before + @BeforeEach public void setUp() { method = new EthCall(blockchainQueries, transactionSimulator); blockHeader = mock(BlockHeader.class); 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 3b4f6a53259..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 @@ -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 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); } 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 3387362a314..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 @@ -53,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"; @@ -73,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); 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 5d8579d468f..6b6f9034101 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 @@ -51,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; @@ -68,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); 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 18f2b006a50..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 @@ -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(); 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..7ecf082759b 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( 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 2f9683de4fc..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 @@ -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()); 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 6370d2c71ce..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 @@ -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); } 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 be37626d920..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 @@ -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); } 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 31e4b07bcd1..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 @@ -41,13 +41,13 @@ 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); } 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/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 a636fc6913a..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 @@ -41,13 +41,13 @@ 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 = @@ -60,7 +60,7 @@ public class EthGetTransactionByHashTest { @Mock private TransactionPool transactionPool; - @Before + @BeforeEach public void setUp() { method = new EthGetTransactionByHash(blockchainQueries, transactionPool); } 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 6a2dbc67c4b..565c58191c5 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 @@ -48,7 +48,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256s; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class EthGetTransactionReceiptTest { private final TransactionReceipt statusReceipt = 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 73a31a3f587..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 @@ -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()); 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 e734f9d80ca..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 @@ -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); } 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 6f26a25525d..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 @@ -30,13 +30,13 @@ 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); } 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 ebb6a7da631..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 @@ -22,14 +22,14 @@ 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(); } 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 177398a8df8..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 @@ -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); } 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 6ad463a8f61..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 @@ -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); } 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 87070c729ce..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 @@ -34,14 +34,17 @@ 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 TransactionPool transactionPool; @@ -50,7 +53,7 @@ public class TxPoolBesuPendingTransactionsTest { private final String TXPOOL_PENDING_TRANSACTIONS_METHOD = "txpool_besuPendingTransactions"; private Set listTrx; - @Before + @BeforeEach public void setUp() { listTrx = getTransactionPool(); method = new TxPoolBesuPendingTransactions(transactionPool); 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 6483b660649..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 @@ -26,13 +26,13 @@ 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 TransactionPool transactionPool; @@ -40,7 +40,7 @@ public class TxPoolBesuStatisticsTest { 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(transactionPool); } 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 6d8a5e7ff06..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 @@ -30,13 +30,13 @@ 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 TransactionPool transactionPool; @@ -46,7 +46,7 @@ public class TxPoolBesuTransactionsTest { private static final String TRANSACTION_HASH = "0xbac263fb39f2a51053fb5e1e52aeb4e980fba9e151aa7e4f12eca95a697aeac9"; - @Before + @BeforeEach public void setUp() { method = new TxPoolBesuTransactions(transactionPool); } 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 7c1edea8b59..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 @@ -23,7 +23,7 @@ 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 { 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 fc02ea467f6..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 @@ -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); 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..0b902f8b13a 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 @@ -41,14 +41,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 AbstractEngineGetPayloadTest { @FunctionalInterface @@ -108,7 +108,7 @@ public AbstractEngineGetPayloadTest(final MethodFactory methodFactory) { @Mock protected EngineCallListener engineCallListener; - @Before + @BeforeEach public void before() { when(mergeContext.retrieveBlockById(mockPid)).thenReturn(Optional.of(mockBlockWithReceipts)); when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); 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 175bf718257..4ff38931cb3 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 @@ -76,15 +76,15 @@ 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.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; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public abstract class AbstractEngineNewPayloadTest { @FunctionalInterface @@ -124,7 +124,7 @@ public AbstractEngineNewPayloadTest(final MethodFactory methodFactory) { @Mock protected EngineCallListener engineCallListener; - @Before + @BeforeEach public void before() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); @@ -373,7 +373,7 @@ public void shouldRespondWithSyncingDuringBackwardsSync() { } @Test - @Ignore + @Disabled public void shouldRespondWithInvalidTerminalPowBlock() { // TODO: implement this as part of https://github.com/hyperledger/besu/issues/3141 // mergeContext is a mock 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..2aabfa68436 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)); 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 1d3dc715de7..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 @@ -28,11 +28,14 @@ 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() { 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 bebbc778458..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 @@ -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 = 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 b045f276e00..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 @@ -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/EngineNewPayloadV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1Test.java index f9a9200d57e..b7bf31f7ee5 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,11 +32,14 @@ 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.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() { 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..2679a386410 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 @@ -16,11 +16,14 @@ import static org.assertj.core.api.Assertions.assertThat; -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 EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { public EngineNewPayloadV2Test() { 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 8e160d275f3..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 @@ -24,8 +24,8 @@ 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); 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 97862fe3383..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 @@ -31,20 +31,20 @@ 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); } 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 75d0a3a3aa4..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 @@ -27,20 +27,20 @@ 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); } 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 719392b4ca8..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 @@ -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)); } 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 132f9f8fbed..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 @@ -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)); } 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 4955472cc3c..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 @@ -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)); } 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 ed620b48016..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 @@ -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)); } 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 e7f7e1a297b..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 @@ -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)); } 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 f7dbd8d2078..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 @@ -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)); } 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 ed85af348d2..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 @@ -29,20 +29,20 @@ 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( 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 c48ea3bf88b..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 @@ -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)); } 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 36e73447a82..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 @@ -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)); } 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 6191f21531a..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 @@ -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)); } 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 118ec77df58..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 @@ -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)); } 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 81a0c5794f5..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 @@ -30,12 +30,12 @@ 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; 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 d9648e11ca3..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 @@ -36,12 +36,12 @@ 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 = 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 0f1c5ed1ae9..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 @@ -31,12 +31,12 @@ 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( 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 27449fa8347..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 @@ -30,12 +30,12 @@ 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( 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 88c82a4ed48..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 @@ -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); 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 bb4c09711a0..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 @@ -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 be9373fa2ad..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 @@ -33,8 +33,8 @@ 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( 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 8c7bdc6fe05..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 @@ -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); } 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 67154d9b7cf..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 @@ -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); 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/PrivGetFilterChangesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetFilterChangesTest.java index a15122e842c..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 @@ -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); } 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 5ff50aed80a..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 @@ -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); } 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 485e27e0099..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 @@ -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); 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 ba1adf4b491..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 @@ -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); 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 bfcf90b93a0..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 @@ -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); } 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 e59cf44ed70..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 @@ -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( 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..fd11a468e56 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 @@ -49,18 +49,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; @@ -98,7 +100,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); @@ -230,7 +232,7 @@ public void traceTransactionToFileShouldReturnEmptyListWhenNoTransaction() { mutableWorldState, blockHash, Optional.of(ImmutableTransactionTraceParams.builder().build()), - traceDir.getRoot().toPath()); + traceDir); assertThat(transactionTraces).isEmpty(); } @@ -273,7 +275,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/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 75fd883eba5..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 @@ -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/PendingPermissionTransactionFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingPermissionTransactionFilterTest.java index 64db24b674a..b08e5f7e8d2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/transaction/pool/PendingPermissionTransactionFilterTest.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 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 PendingPermissionTransactionFilterTest( + @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 20c726cc119..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 @@ -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"); 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 551281e8749..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 @@ -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,8 +164,6 @@ 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 = @@ -173,11 +174,13 @@ public void handlerBatchRequestContainingErrorsShouldRespondWithBatchErrors( 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, 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, 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, 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 = @@ -256,11 +261,13 @@ public void onInvalidJsonRpcParametersExceptionProcessingRequestShouldRespondInv final JsonRpcErrorResponse expectedResponse = 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,8 +275,7 @@ 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 = @@ -278,11 +284,13 @@ public void onExceptionProcessingRequestShouldRespondInternalError(final TestCon final JsonRpcErrorResponse expectedResponse = 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 09127be7084..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 @@ -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); 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 b20af5ad3c6..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 @@ -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); 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 12ffda3bae7..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 @@ -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( 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 5c7e4602c00..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 @@ -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( 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..bc9bc2afd0c 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( @@ -123,10 +126,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..c5442c434ed 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( @@ -119,22 +123,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 +149,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 +173,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 +233,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 { 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 { From a5eee40fced7e80e400946be7b3cfad8a778ffe8 Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Tue, 25 Jul 2023 21:34:06 +0530 Subject: [PATCH 20/51] junit4 to junit5 for ethereum/blockcreation (#5714) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/blockcreation/build.gradle | 3 --- .../AbstractBlockTransactionSelectorTest.java | 15 ++++++----- .../AbstractMiningCoordinatorTest.java | 6 ++--- .../blockcreation/BlockMinerTest.java | 2 +- .../DefaultBlockSchedulerTest.java | 2 +- .../HashRateMiningCoordinatorTest.java | 26 ++++--------------- .../IncrementingNonceGeneratorTest.java | 2 +- ...FeeMarketBlockTransactionSelectorTest.java | 2 +- .../blockcreation/PoWMinerExecutorTest.java | 2 +- .../PoWMiningCoordinatorTest.java | 6 ++--- 10 files changed, 25 insertions(+), 41 deletions(-) diff --git a/ethereum/blockcreation/build.gradle b/ethereum/blockcreation/build.gradle index d813869db6a..7fc35a6ec10 100644 --- a/ethereum/blockcreation/build.gradle +++ b/ethereum/blockcreation/build.gradle @@ -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/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index 16a6c540d47..517e3a79cd1 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 @@ -76,14 +76,17 @@ 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; @@ -109,7 +112,7 @@ public abstract class AbstractBlockTransactionSelectorTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) protected EthContext ethContext; - @Before + @BeforeEach public void setup() { genesisConfigFile = getGenesisConfigFile(); protocolSchedule = createProtocolSchedule(); 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/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index 6179e355a79..bb6701fc0f7 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 @@ -42,7 +42,7 @@ import java.util.List; import java.util.function.Function; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class LondonFeeMarketBlockTransactionSelectorTest extends AbstractBlockTransactionSelectorTest { 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 01e09a74e08..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 @@ -41,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(); 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); } From 464c0902b83e5b22d35e523829d1eda9df9f83ea Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Tue, 25 Jul 2023 23:39:41 +0530 Subject: [PATCH 21/51] ethereum/part5 - migrated tests from Junit4 to Junit5 (#5717) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/ethstats/build.gradle | 4 +--- .../besu/ethstats/EthStatsServiceTest.java | 15 +++++++++------ .../ethstats/util/EthStatsConnectOptionsTest.java | 2 +- .../ethstats/util/PrimusHeartBeatsHelperTest.java | 2 +- ethereum/evmtool/build.gradle | 1 - .../evmtool/CodeValidationSubCommandTest.java | 2 +- .../besu/evmtool/StateTestSubCommandTest.java | 2 +- ethereum/mock-p2p/build.gradle | 3 --- .../ethereum/p2p/testing/MockNetworkTest.java | 2 +- 9 files changed, 15 insertions(+), 18 deletions(-) diff --git a/ethereum/ethstats/build.gradle b/ethereum/ethstats/build.gradle index 52fe38473ce..2097f0f1bb6 100644 --- a/ethereum/ethstats/build.gradle +++ b/ethereum/ethstats/build.gradle @@ -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/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 df8b99aea53..c5604d7a52c 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -59,7 +59,6 @@ dependencies { 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' 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/mock-p2p/build.gradle b/ethereum/mock-p2p/build.gradle index bfab38e98c7..373e25be3cf 100644 --- a/ethereum/mock-p2p/build.gradle +++ b/ethereum/mock-p2p/build.gradle @@ -37,9 +37,6 @@ dependencies { implementation 'io.vertx:vertx-core' 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 { From a5fe79f1adf0cb71ec29366383cd49b92967dd9e Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Wed, 26 Jul 2023 00:11:08 +0530 Subject: [PATCH 22/51] ethereum/p2p - migrated tests from Junit4 to Junit5 (#5718) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/p2p/build.gradle | 4 +- .../config/DiscoveryConfigurationTest.java | 2 +- .../p2p/discovery/PeerDiscoveryAgentTest.java | 2 +- .../discovery/PeerDiscoveryBondingTest.java | 2 +- .../PeerDiscoveryBootstrappingTest.java | 2 +- .../PeerDiscoveryPacketPcapSedesTest.java | 2 +- .../PeerDiscoveryPacketSedesTest.java | 2 +- .../PeerDiscoveryTimestampsTest.java | 2 +- .../p2p/discovery/internal/BucketTest.java | 4 +- .../internal/ENRRequestPacketDataTest.java | 2 +- .../internal/ENRResponsePacketDataTest.java | 2 +- .../internal/FindNeighborsPacketDataTest.java | 2 +- .../internal/NeighborsPacketDataTest.java | 2 +- .../p2p/discovery/internal/PacketTest.java | 2 +- .../discovery/internal/PacketTypeTest.java | 2 +- ...overyControllerDistanceCalculatorTest.java | 2 +- .../internal/PeerDiscoveryControllerTest.java | 10 +-- .../PeerDiscoveryTableRefreshTest.java | 2 +- .../internal/PeerRequirementCombineTest.java | 53 ++++++-------- .../p2p/discovery/internal/PeerTableTest.java | 2 +- .../internal/PingPacketDataTest.java | 2 +- .../internal/PongPacketDataTest.java | 2 +- .../RecursivePeerRefreshStateTest.java | 6 +- .../p2p/network/DefaultP2PNetworkTest.java | 12 ++-- .../NetworkingServiceLifecycleTest.java | 71 +++++++++---------- .../ethereum/p2p/network/P2PNetworkTest.java | 12 ++-- .../p2p/network/P2PPlainNetworkTest.java | 12 ++-- .../p2p/network/PeerDenylistManagerTest.java | 2 +- .../p2p/peers/DefaultLocalNodeTest.java | 2 +- .../ethereum/p2p/peers/EnodeURLImplTest.java | 2 +- .../p2p/peers/MaintainedPeersTest.java | 2 +- .../besu/ethereum/p2p/peers/PeerTest.java | 21 +++--- .../PeerPermissionsDenylistTest.java | 2 +- .../p2p/permissions/PeerPermissionsTest.java | 2 +- .../p2p/plain/MessageHandlerTest.java | 8 +-- .../besu/ethereum/p2p/rlpx/RlpxAgentTest.java | 10 +-- .../AbstractPeerConnectionTest.java | 6 +- .../rlpx/connections/netty/DeFramerTest.java | 6 +- .../NettyTLSConnectionInitializerTest.java | 15 ++-- .../netty/TLSContextFactoryTest.java | 9 +-- .../ethereum/p2p/rlpx/framing/FramerTest.java | 2 +- .../rlpx/framing/SnappyCompressorTest.java | 2 +- .../handshake/ecies/ECIESHandshakeTest.java | 5 +- .../handshake/ecies/EncryptedMessageTest.java | 2 +- .../InitiatorHandshakeMessageV4Test.java | 2 +- .../rlpx/wire/CapabilityMultiplexerTest.java | 2 +- .../p2p/rlpx/wire/WireMessagesSedesTest.java | 2 +- .../wire/messages/DisconnectMessageTest.java | 2 +- 48 files changed, 158 insertions(+), 168 deletions(-) diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 0775a51d2a9..ed2f9aa1e0e 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -77,11 +77,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/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 00cbccb126a..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 @@ -64,15 +64,15 @@ 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 = @@ -92,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)); 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 { From 8606db603221d352d836495e2bbcd3c1dcf26bc6 Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Wed, 26 Jul 2023 00:46:43 +0530 Subject: [PATCH 23/51] ethereum/permissioning - migrated tests from Junit4 to Junit5 (#5719) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/permissioning/build.gradle | 4 +--- ...untLocalConfigPermissioningControllerTest.java | 12 ++++++------ .../permissioning/AllowlistPersistorTest.java | 10 +++++----- ...ocalPermissioningConfigurationBuilderTest.java | 2 +- .../LocalPermissioningConfigurationTest.java | 2 +- ...odeLocalConfigPermissioningControllerTest.java | 12 ++++++------ ...eSmartContractPermissioningControllerTest.java | 8 ++++---- ...martContractV2PermissioningControllerTest.java | 6 +++--- ...nSmartContractPermissioningControllerTest.java | 8 ++++---- ...AccountPermissioningControllerFactoryTest.java | 8 ++++---- .../AccountPermissioningControllerTest.java | 12 ++++++------ ...nsufficientPeersPermissioningProviderTest.java | 15 +++++++++------ .../NodePermissioningControllerFactoryTest.java | 15 +++++++++------ .../node/NodePermissioningControllerTest.java | 12 ++++++------ .../node/PeerPermissionsAdapterTest.java | 2 +- .../SyncStatusNodePermissioningProviderTest.java | 12 ++++++------ 16 files changed, 72 insertions(+), 68 deletions(-) diff --git a/ethereum/permissioning/build.gradle b/ethereum/permissioning/build.gradle index a0493360a15..eaf36c8fda6 100644 --- a/ethereum/permissioning/build.gradle +++ b/ethereum/permissioning/build.gradle @@ -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/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/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 a7f01997d49..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 @@ -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 85ad5596fe7..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 @@ -34,12 +34,12 @@ 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; 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 5ed0d1e66c7..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 @@ -27,13 +27,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 AccountPermissioningControllerTest { private AccountPermissioningController permissioningController; @@ -41,7 +41,7 @@ public class AccountPermissioningControllerTest { @Mock private AccountLocalConfigPermissioningController localConfigController; @Mock private TransactionSmartContractPermissioningController smartContractController; - @Before + @BeforeEach public void before() { permissioningController = new AccountPermissioningController( 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 afba9bb18fb..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,7 +63,7 @@ public class NodePermissioningControllerFactoryTest { SmartContractPermissioningConfiguration smartContractPermissioningConfiguration; PermissioningConfiguration config; - @Before + @BeforeEach public void before() { when(transactionSimulator.doesAddressExistAtHead(any())).thenReturn(Optional.of(true)); } 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 512b752895b..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 @@ -33,13 +33,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 NodePermissioningControllerTest { private static final EnodeURL enode1 = @@ -56,7 +56,7 @@ public class NodePermissioningControllerTest { private NodePermissioningController controller; - @Before + @BeforeEach public void before() { syncStatusNodePermissioningProviderOptional = Optional.of(syncStatusNodePermissioningProvider); List emptyProviders = new ArrayList<>(); 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); From e0cb1fe3bc295352901abe35897b141c859fa3f6 Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Wed, 26 Jul 2023 11:44:13 +0530 Subject: [PATCH 24/51] ethereum/core - migrated tests from Junit4 to Junit5 (#5715) * ethereum/core - migrated tests from Junit4 to Junit5 Signed-off-by: Nischal Sharma * fixed PermissionTransactionValidatorTest Signed-off-by: Nischal Sharma --------- Signed-off-by: Nischal Sharma --- ethereum/core/build.gradle | 6 +- .../ethereum/core/BlockSyncTestUtils.java | 10 +- .../ethereum/core/BlockchainSetupUtil.java | 5 - .../BlockImportExceptionHandlingTest.java | 6 +- .../ethereum/MainnetBlockValidatorTest.java | 6 +- .../bonsai/AbstractIsolationTests.java | 75 ++-- .../bonsai/BonsaiSnapshotIsolationTests.java | 8 +- .../bonsai/BonsaiWorldStateArchiveTest.java | 19 +- .../BonsaiWorldStateKeyValueStorageTest.java | 155 ++++--- .../bonsai/CachedMerkleTrieLoaderTest.java | 6 +- .../besu/ethereum/bonsai/LogRollingTests.java | 12 +- .../bonsai/trielog/TrieLogFactoryTests.java | 8 +- .../bonsai/trielog/TrieLogLayerTests.java | 6 +- .../bonsai/trielog/TrieLogManagerTests.java | 12 +- .../ethereum/chain/DefaultBlockchainTest.java | 2 +- .../besu/ethereum/chain/GenesisStateTest.java | 2 +- .../core/AccountTransactionOrderTest.java | 2 +- .../core/BlockValueCalculatorTest.java | 2 +- .../besu/ethereum/core/LogTest.java | 2 +- .../ethereum/core/TransactionBuilderTest.java | 2 +- .../core/TransactionIntegrationTest.java | 2 +- .../ethereum/core/TransactionReceiptTest.java | 2 +- .../besu/ethereum/core/UtilTest.java | 2 +- .../feemarket/BaseFeeMarketBaseFeeTest.java | 36 +- .../core/feemarket/BaseFeeMarketTest.java | 2 +- .../CoinbaseFeePriceCalculatorTest.java | 51 +-- .../TransactionPriceCalculatorTest.java | 178 ++++---- .../fixed/FixedProtocolScheduleTest.java | 2 +- .../ForkIdBackwardCompatibilityTest.java | 79 ++-- .../besu/ethereum/forkid/ForkIdTest.java | 391 +++++++----------- .../BaseFeeBlockBodyValidatorTest.java | 12 +- .../mainnet/BlockHeaderValidatorTest.java | 6 +- .../ethereum/mainnet/BodyValidationTest.java | 2 +- .../mainnet/DefaultProtocolScheduleTest.java | 6 +- .../besu/ethereum/mainnet/EtcHashTest.java | 2 +- .../besu/ethereum/mainnet/EthHashTest.java | 2 +- .../ethereum/mainnet/IntrinsicGasTest.java | 95 ++--- .../MainnetBlockHeaderValidatorTest.java | 8 +- .../mainnet/MainnetBlockImporterTest.java | 12 +- ...nnetPrecompiledContractRegistriesTest.java | 8 +- .../mainnet/MainnetProtocolScheduleTest.java | 2 +- .../MainnetTransactionProcessorTest.java | 8 +- .../MainnetTransactionValidatorTest.java | 11 +- .../PermissionTransactionValidatorTest.java | 8 +- .../besu/ethereum/mainnet/PoWSolverTest.java | 8 +- .../mainnet/PrivacyBlockProcessorTest.java | 12 +- .../mainnet/ProtocolScheduleBuilderTest.java | 12 +- .../mainnet/ProtocolSpecAdaptersTest.java | 8 +- .../ethereum/mainnet/RefundSstoreGasTest.java | 164 ++++---- .../TargetingGasLimitCalculatorTest.java | 2 +- .../TransactionValidationParamsTest.java | 2 +- .../mainnet/ValidationResultTest.java | 2 +- .../feemarket/LondonFeeMarketTest.java | 2 +- .../feemarket/ZeroBaseFeeMarketTest.java | 6 +- .../AncestryValidationRuleTest.java | 2 +- ...BlockHeaderGasPriceValidationRuleTest.java | 6 +- .../ConstantFieldValidationRuleTest.java | 2 +- .../ExtraDataMaxLengthValidationRuleTest.java | 2 +- .../GasLimitElasticityValidationRuleTest.java | 69 ++-- ...tyValidationRuleZeroBaseFeeMarketTest.java | 68 ++- ...sLimitRangeAndDeltaValidationRuleTest.java | 111 ++--- .../GasUsageValidationRuleTest.java | 39 +- .../ProofOfWorkValidationRuleTest.java | 92 +++-- .../TimestampValidationRuleTest.java | 2 +- ...lexiblePrivacyPrecompiledContractTest.java | 10 +- .../PrivacyPluginPrecompiledContractTest.java | 6 +- .../ChainHeadPrivateNonceProviderTest.java | 12 +- .../FlexiblePrivacyControllerTest.java | 17 +- .../ethereum/privacy/FlexibleUtilTest.java | 8 +- ...tiTenancyPrivacyControllerOnchainTest.java | 12 +- .../MultiTenancyPrivacyControllerTest.java | 12 +- .../privacy/PrivacyGroupUtilTest.java | 2 +- .../privacy/PrivateMetadataUpdaterTest.java | 12 +- .../PrivateStateGenesisAllocatorTest.java | 2 +- .../privacy/PrivateStateRootResolverTest.java | 10 +- .../PrivateTransactionLocatorTest.java | 15 +- .../privacy/PrivateTransactionTest.java | 2 +- .../PrivateTransactionValidatorTest.java | 12 +- .../privacy/PrivateWorldStateReaderTest.java | 19 +- ...estrictedDefaultPrivacyControllerTest.java | 17 +- ...ngPrivateMarkerTransactionFactoryTest.java | 8 +- ...ngPrivateMarkerTransactionFactoryTest.java | 8 +- .../PrivateStateKeyValueStorageTest.java | 6 +- .../PrivateStorageMigrationTest.java | 15 +- .../proof/WorldStateProofProviderTest.java | 12 +- .../WorldStateRangeProofProviderTest.java | 6 +- .../KeyValueStorageWorldStateStorageTest.java | 2 +- .../TransactionSimulatorResultTest.java | 12 +- .../transaction/TransactionSimulatorTest.java | 15 +- .../util/BlockchainUtilParameterizedTest.java | 39 +- .../ethereum/util/RawBlockIteratorTest.java | 14 +- .../ethereum/vm/AbstractRetryingTest.java | 6 +- .../besu/ethereum/vm/AddressTest.java | 2 +- .../vm/CachingBlockHashLookupTest.java | 16 +- .../ethereum/vm/DebugOperationTracerTest.java | 8 +- .../vm/EstimateGasOperationTracerTest.java | 12 +- .../besu/ethereum/vm/MemoryTest.java | 2 +- .../DefaultMutableWorldStateTest.java | 2 +- .../worldstate/MarkSweepPrunerTest.java | 8 +- .../besu/ethereum/worldstate/PrunerTest.java | 8 +- .../worldstate/StateTrieAccountValueTest.java | 2 +- 101 files changed, 1034 insertions(+), 1221 deletions(-) diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 4f2db3119d7..92186b04e2e 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -75,8 +75,6 @@ dependencies { testImplementation project(':testutil') testImplementation project(path: ':plugins:rocksdb') - - testImplementation 'junit:junit' testImplementation 'org.apache.logging.log4j:log4j-core' testImplementation 'io.tmio:tuweni-bytes' testImplementation 'io.tmio:tuweni-io' @@ -88,8 +86,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') @@ -104,7 +100,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/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/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 1cd869895e2..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 @@ -70,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; @@ -84,9 +82,8 @@ 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; @@ -136,9 +133,9 @@ public abstract class AbstractIsolationTests { 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) @@ -171,44 +168,38 @@ public void createStorage() { // 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 { 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..8f717e7de31 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 @@ -46,15 +46,18 @@ 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(); @@ -69,7 +72,7 @@ public class BonsaiWorldStateArchiveTest { @Mock TrieLogManager trieLogManager; - @Before + @BeforeEach public void setUp() { when(storageProvider.getStorageBySegmentIdentifier(any(KeyValueSegmentIdentifier.class))) .thenReturn(keyValueStorage); @@ -237,7 +240,7 @@ 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); 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..6652442a30a 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 @@ -44,67 +44,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") + public 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") + public 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") + public 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") + public void getNodeData_returnsEmptyValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); assertThat(storage.getNodeData(null, null)).isEmpty(); } - @Test - public void getNodeData_returnsEmptyNode() { + @ParameterizedTest + @MethodSource("data") + public 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") + public void getCode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + setUp(flatDbMode); storage .updater() .putCode(Hash.EMPTY, MerkleTrie.EMPTY_TRIE_NODE) @@ -115,16 +116,20 @@ public void getCode_saveAndGetSpecialValues() { .contains(MerkleTrie.EMPTY_TRIE_NODE); } - @Test - public void getCode_saveAndGetRegularValue() { + @ParameterizedTest + @MethodSource("data") + public 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") + public void getAccountStateTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + setUp(flatDbMode); storage .updater() .putAccountStateTrieNode( @@ -137,8 +142,10 @@ public void getAccountStateTrieNode_saveAndGetSpecialValues() { assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, Hash.EMPTY)).contains(Bytes.EMPTY); } - @Test - public void getAccountStateTrieNode_saveAndGetRegularValue() { + @ParameterizedTest + @MethodSource("data") + public void getAccountStateTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final Bytes location = Bytes.fromHexString("0x01"); final Bytes bytes = Bytes.fromHexString("0x123456"); @@ -147,8 +154,10 @@ public void getAccountStateTrieNode_saveAndGetRegularValue() { assertThat(storage.getAccountStateTrieNode(location, Hash.hash(bytes))).contains(bytes); } - @Test - public void getAccountStorageTrieNode_saveAndGetSpecialValues() { + @ParameterizedTest + @MethodSource("data") + public void getAccountStorageTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + setUp(flatDbMode); storage .updater() @@ -168,8 +177,10 @@ public void getAccountStorageTrieNode_saveAndGetSpecialValues() { .contains(Bytes.EMPTY); } - @Test - public void getAccountStorageTrieNode_saveAndGetRegularValue() { + @ParameterizedTest + @MethodSource("data") + public void getAccountStorageTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final Hash accountHash = Hash.hash(Address.fromHexString("0x1")); final Bytes location = Bytes.fromHexString("0x01"); final Bytes bytes = Bytes.fromHexString("0x123456"); @@ -183,9 +194,11 @@ public void getAccountStorageTrieNode_saveAndGetRegularValue() { .contains(bytes); } - @Test - public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.FULL); + @ParameterizedTest + @MethodSource("data") + public 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); @@ -213,9 +226,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") + public 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 = @@ -240,9 +255,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") + public void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flatDbMode) { + setUp(flatDbMode); + Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); @@ -270,9 +287,11 @@ public void shouldUsePartialDBStrategyAfterDowngradingMode() { .contains(accounts.firstEntry().getValue()); } - @Test - public void getStorage_loadFromTrieWhenEmptyWithPartialMode() { - Assume.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); + @ParameterizedTest + @MethodSource("data") + public 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 = @@ -317,9 +336,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") + public 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); @@ -335,8 +356,10 @@ public void getStorage_loadFromTrieWhenEmptyWithFullMode() { storage.clearFlatDatabase(); } - @Test - public void clear_reloadFlatDbStrategy() { + @ParameterizedTest + @MethodSource("data") + public void clear_reloadFlatDbStrategy(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); // save world state root hash @@ -353,8 +376,10 @@ public void clear_reloadFlatDbStrategy() { assertThat(storage.getAccount(Hash.ZERO)).isEmpty(); } - @Test - public void reconcilesNonConflictingUpdaters() { + @ParameterizedTest + @MethodSource("data") + public void reconcilesNonConflictingUpdaters(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final Hash accountHashA = Hash.hash(Address.fromHexString("0x1")); final Hash accountHashB = Hash.hash(Address.fromHexString("0x2")); final Hash accountHashD = Hash.hash(Address.fromHexString("0x4")); @@ -377,13 +402,17 @@ public void reconcilesNonConflictingUpdaters() { assertThat(storage.getCode(Hash.hash(bytesC), accountHashD)).contains(bytesC); } - @Test - public void isWorldStateAvailable_defaultIsFalse() { + @ParameterizedTest + @MethodSource("data") + public 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") + public void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flatDbMode) { + setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); final Bytes rootHashKey = Bytes32.fromHexString("0x01"); @@ -393,8 +422,10 @@ public void isWorldStateAvailable_StateAvailableByRootHash() { .isTrue(); } - @Test - public void isWorldStateAvailable_afterCallingSaveWorldstate() { + @ParameterizedTest + @MethodSource("data") + public 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..cbb125647bf 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,8 +39,8 @@ 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 { @@ -55,7 +55,7 @@ public class CachedMerkleTrieLoaderTest { private MerkleTrie trie; - @Before + @BeforeEach public void setup() { trie = TrieGenerator.generateTrie( 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..b2cad642fc2 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 @@ -48,12 +48,12 @@ 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; @@ -122,7 +122,7 @@ public class LogRollingTests { null, new MainnetBlockHeaderFunctions()); - @Before + @BeforeEach public void createStorage() { provider = new InMemoryKeyValueStorageProvider(); final CachedMerkleTrieLoader cachedMerkleTrieLoader = 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..63e71ece52a 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 @@ -30,7 +30,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 { 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 0a4c3aad964..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 @@ -26,7 +26,7 @@ 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 e6bc265918c..0adcaa5b8c4 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 @@ -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 = 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/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 57308aff27d..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 @@ -25,15 +25,14 @@ 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 7dee20bab8c..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 @@ -32,13 +32,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 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..508af1f5a45 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,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** Tests for {@link BodyValidation}. */ public final class BodyValidationTest { 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 ff0bca70520..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,14 +41,14 @@ 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; 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 2475d618132..dd4d19115da 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 @@ -49,12 +49,15 @@ import com.google.common.base.Suppliers; 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; +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 = 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 index e25a31ad8be..0b4c948f55e 100644 --- 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 @@ -39,13 +39,13 @@ import java.util.function.Supplier; import com.google.common.base.Suppliers; -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.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class PermissionTransactionValidatorTest extends MainnetTransactionValidatorTest { private static final Supplier SIGNATURE_ALGORITHM = 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/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/LondonFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java index 4c304ce712b..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 @@ -25,7 +25,7 @@ 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 4892bceb1fd..3c77f9d2b5d 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 @@ -26,8 +26,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 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); } 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/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 d1156abd175..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); 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 641d4ffce65..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 @@ -29,11 +29,11 @@ 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 f425eaf39bf..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 @@ -26,11 +26,11 @@ 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 c6b0352eff6..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 @@ -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..08f83d146bb 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); } 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 8962ef56c9c..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 @@ -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..d4b22c72622 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; 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..5a6096047b4 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(); 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..7e0af71fe7d 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(); 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 { From dbd27f05cadfea927ba057dbc30870b5ba32c076 Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Wed, 26 Jul 2023 12:14:43 +0530 Subject: [PATCH 25/51] ethereum/eth - migrated tests from Junit4 to Junit5 (#5716) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/eth/build.gradle | 4 - .../besu/ethereum/eth/EthProtocolTest.java | 2 +- .../ethereum/eth/manager/ChainStateTest.java | 2 +- .../ethereum/eth/manager/EthPeerTest.java | 2 +- .../ethereum/eth/manager/EthPeersTest.java | 6 +- .../eth/manager/EthProtocolManagerTest.java | 6 +- .../eth/manager/EthSchedulerShutdownTest.java | 6 +- .../eth/manager/EthSchedulerTest.java | 6 +- .../ethereum/eth/manager/EthServerTest.java | 2 +- .../eth/manager/PeerReputationTest.java | 7 +- .../eth/manager/RequestManagerTest.java | 2 +- .../eth/manager/bounded/BoundedQueueTest.java | 2 +- .../ethtaskutils/AbstractMessageTaskTest.java | 10 +- .../ethtaskutils/PeerMessageTaskTest.java | 2 +- .../ethtaskutils/RetryingMessageTaskTest.java | 6 +- .../RetryingSwitchingPeerMessageTaskTest.java | 2 +- .../eth/manager/task/AbstractEthTaskTest.java | 8 +- .../task/AbstractRetryingPeerTaskTest.java | 8 +- ...PooledTransactionsFromPeerFetcherTest.java | 15 +- .../task/GetBlockFromPeerTaskTest.java | 2 +- .../task/GetBodiesFromPeerTaskTest.java | 2 +- .../GetHeadersFromPeerByHashTaskTest.java | 8 +- .../GetHeadersFromPeerByNumberTaskTest.java | 8 +- .../RetryingGetBlockFromPeersTaskTest.java | 8 +- .../RetryingGetNodeDataFromPeerTaskTest.java | 8 +- .../eth/manager/task/WaitForPeerTaskTest.java | 6 +- .../manager/task/WaitForPeersTaskTest.java | 6 +- .../eth/messages/BlockBodiesMessageTest.java | 6 +- .../eth/messages/BlockHeadersMessageTest.java | 2 +- .../messages/GetBlockBodiesMessageTest.java | 2 +- .../messages/GetBlockHeadersMessageTest.java | 2 +- .../eth/messages/GetNodeDataMessageTest.java | 2 +- .../GetPooledTransactionsMessageTest.java | 2 +- .../eth/messages/GetReceiptsMessageTest.java | 2 +- .../LimitedTransactionsMessagesTest.java | 2 +- .../eth/messages/MessageWrapperTest.java | 2 +- .../messages/NewBlockHashesMessageTest.java | 2 +- .../eth/messages/NewBlockMessageTest.java | 2 +- ...NewPooledTransactionHashesMessageTest.java | 2 +- .../eth/messages/NodeDataMessageTest.java | 2 +- .../PooledTransactionsMessageTest.java | 2 +- .../eth/messages/ReceiptsMessageTest.java | 2 +- .../eth/messages/StatusMessageTest.java | 2 +- .../eth/messages/TransactionsMessageTest.java | 2 +- .../snap/AccountRangeMessageTest.java | 2 +- .../messages/snap/BytecodeMessageTest.java | 2 +- .../snap/GetAccountRangeMessageTest.java | 2 +- .../messages/snap/GetBytecodeMessageTest.java | 2 +- .../snap/GetStorageRangeMessageTest.java | 2 +- .../messages/snap/GetTrieNodeMessageTest.java | 2 +- .../snap/StorageRangeMessageTest.java | 2 +- .../messages/snap/TrieNodeMessageTest.java | 2 +- .../AbstractPeerBlockValidatorTest.java | 2 +- .../DaoForkPeerValidatorTest.java | 2 +- .../PeerValidatorRunnerTest.java | 2 +- .../RequiredBlocksPeerValidatorTest.java | 2 +- .../eth/sync/RangeHeadersFetcherTest.java | 10 +- .../backwardsync/BackwardSyncAlgSpec.java | 15 +- .../backwardsync/BackwardSyncContextTest.java | 15 +- .../backwardsync/BackwardSyncStepTest.java | 15 +- .../backwardsync/ForwardSyncStepTest.java | 15 +- .../InMemoryBackwardChainTest.java | 12 +- .../CheckPointBlockImportStepTest.java | 6 +- .../checkpointsync/CheckPointSourceTest.java | 6 +- .../CheckPointSyncChainDownloaderTest.java | 48 +++--- .../fastsync/DownloadReceiptsStepTest.java | 10 +- .../fastsync/FastDownloaderFactoryTest.java | 11 +- .../sync/fastsync/FastSyncActionsTest.java | 141 +++++++++++------ .../fastsync/FastSyncChainDownloaderTest.java | 54 +++---- .../sync/fastsync/FastSyncDownloaderTest.java | 6 +- .../fastsync/FastSyncStateStorageTest.java | 21 ++- .../FastSyncValidationPolicyTest.java | 2 +- .../fastsync/PivotBlockConfirmerTest.java | 68 ++++---- .../fastsync/PivotBlockRetrieverTest.java | 83 +++++----- .../worldstate/CompleteTaskStepTest.java | 2 +- .../FastWorldDownloadStateTest.java | 91 ++++++----- .../FastWorldStateDownloaderTest.java | 32 ++-- .../worldstate/LoadLocalDataStepTest.java | 2 +- .../worldstate/NodeDataRequestTest.java | 2 +- .../worldstate/PersistDataStepTest.java | 2 +- .../worldstate/RequestDataStepTest.java | 6 +- .../BetterSyncTargetEvaluatorTest.java | 6 +- .../fullsync/FullImportBlockStepTest.java | 12 +- .../FullSyncChainDownloaderForkTest.java | 14 +- .../fullsync/FullSyncChainDownloaderTest.java | 92 ++++++----- ...DownloaderTotalTerminalDifficultyTest.java | 49 +++--- .../sync/fullsync/FullSyncDownloaderTest.java | 48 +++--- .../fullsync/FullSyncTargetManagerTest.java | 61 ++++---- .../sync/snapsync/CompleteTaskStepTest.java | 6 +- .../DynamicPivotBlockManagerTest.java | 6 +- .../sync/snapsync/LoadLocalDataStepTest.java | 6 +- .../sync/snapsync/PersistDataStepTest.java | 6 +- .../eth/sync/snapsync/RangeManagerTest.java | 2 +- .../snapsync/SnapWorldDownloadStateTest.java | 147 +++++++++++------- .../eth/sync/snapsync/StackTrieTest.java | 2 +- ...ntFlatDatabaseHealingRangeRequestTest.java | 15 +- ...geFlatDatabaseHealingRangeRequestTest.java | 12 +- .../sync/state/PendingBlocksManagerTest.java | 6 +- .../eth/sync/state/SyncStateTest.java | 12 +- .../state/cache/PendingBlockCacheTest.java | 6 +- .../sync/tasks/CompleteBlocksTaskTest.java | 2 +- ...neCommonAncestorTaskParameterizedTest.java | 41 ++--- .../DetermineCommonAncestorTaskTest.java | 6 +- .../tasks/DownloadHeaderSequenceTaskTest.java | 2 +- .../tasks/GetReceiptsForHeadersTaskTest.java | 2 +- .../eth/sync/tasks/PersistBlockTaskTest.java | 100 +++++++----- ...yingGetHeaderFromPeerByNumberTaskTest.java | 6 +- ...actionsLayeredPendingTransactionsTest.java | 15 +- ...TransactionHashesMessageProcessorTest.java | 15 +- ...ledTransactionHashesMessageSenderTest.java | 6 +- .../PeerTransactionTrackerTest.java | 2 +- .../TransactionBroadcasterTest.java | 15 +- .../TransactionPoolFactoryTest.java | 15 +- ...TransactionPoolReplacementHandlerTest.java | 30 ++-- .../TransactionReplacementRulesTest.java | 27 +--- .../TransactionsMessageProcessorTest.java | 12 +- .../TransactionsMessageSenderTest.java | 2 +- .../LayeredPendingTransactionsLegacyTest.java | 8 +- .../LayeredPendingTransactionsLondonTest.java | 2 +- .../AbstractPendingTransactionsTestBase.java | 2 +- 120 files changed, 925 insertions(+), 776 deletions(-) diff --git a/ethereum/eth/build.gradle b/ethereum/eth/build.gradle index 68a40750b7c..a40b49afffb 100644 --- a/ethereum/eth/build.gradle +++ b/ethereum/eth/build.gradle @@ -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/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 fcc66b56916..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 @@ -58,9 +58,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; /** * @param The type of data being requested from the network @@ -92,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); @@ -103,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); 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/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 be86b802e65..fccdae23f8e 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 @@ -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 { 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 6a5b8344c51..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 @@ -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 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 eb9f9dc54bb..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 @@ -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/ForwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java index cf03c676ad9..77308ebcc3b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java @@ -49,14 +49,17 @@ import javax.annotation.Nonnull; 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 class ForwardSyncStepTest { public static final int REMOTE_HEIGHT = 50; @@ -77,7 +80,7 @@ public class ForwardSyncStepTest { 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/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 e4e116b8a8c..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,7 +34,7 @@ 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 { 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..cfe5f2697fc 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,14 +48,14 @@ 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) +@ExtendWith(MockitoExtension.class) public class StorageFlatDatabaseHealingRangeRequestTest { @Mock private SnapWorldDownloadState downloadState; @@ -74,7 +74,7 @@ public class StorageFlatDatabaseHealingRangeRequestTest { private Hash account0Hash; private Hash account0StorageRoot; - @Before + @BeforeEach public void setup() { final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); worldStateStorage = 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/AbstractTransactionsLayeredPendingTransactionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionsLayeredPendingTransactionsTest.java index 25275043432..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 @@ -77,16 +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 = @@ -133,7 +136,7 @@ protected abstract PendingTransactions createPendingTransactionsSorter( protected abstract FeeMarket getFeeMarket(); - @Before + @BeforeEach public void setUp() { executionContext = createExecutionContextTestFixture(); protocolContext = executionContext.getProtocolContext(); 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 c3a609ef292..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 @@ -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/TransactionBroadcasterTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionBroadcasterTest.java index 8664b0082d9..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 @@ -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 8435b8b3ca4..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 @@ -61,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; @@ -90,7 +93,7 @@ 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); 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 0fa5df961cf..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 @@ -30,14 +30,11 @@ 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 c4097ca85da..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 @@ -30,14 +30,11 @@ 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/LayeredPendingTransactionsLegacyTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayeredPendingTransactionsLegacyTest.java index 83bce273019..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 @@ -44,12 +44,12 @@ 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 87d7c650b2f..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 @@ -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 { From d923b8eb8fafc743114728499c135a418697da8d Mon Sep 17 00:00:00 2001 From: Nischal Sharma Date: Wed, 26 Jul 2023 12:43:17 +0530 Subject: [PATCH 26/51] ethereum/part8 - migrated tests from Junit4 to Junit5 (#5720) Signed-off-by: Nischal Sharma Co-authored-by: Sally MacFarlane --- ethereum/retesteth/build.gradle | 3 --- .../retesteth/methods/TestImportRawBlockTest.java | 6 +++--- .../retesteth/methods/TestSetChainParamsTest.java | 6 +++--- ethereum/rlp/build.gradle | 3 --- .../besu/ethereum/rlp/BytesValueRLPInputTest.java | 2 +- .../besu/ethereum/rlp/BytesValueRLPOutputTest.java | 2 +- .../java/org/hyperledger/besu/ethereum/rlp/RLPTest.java | 2 +- ethereum/trie/build.gradle | 4 +--- .../besu/ethereum/trie/AllNodesVisitorTest.java | 8 ++++---- .../besu/ethereum/trie/CompactEncodingTest.java | 2 +- .../ethereum/trie/RangeStorageEntriesCollectorTest.java | 2 +- .../besu/ethereum/trie/SnapPutVisitorTest.java | 2 +- .../hyperledger/besu/ethereum/trie/TrieIteratorTest.java | 2 +- .../besu/ethereum/trie/TrieNodeDecoderTest.java | 2 +- .../trie/patricia/AbstractMerklePatriciaTrieTest.java | 8 ++++---- .../trie/patricia/StoredMerklePatriciaTrieTest.java | 2 +- ethereum/verkletrie/build.gradle | 3 --- .../ethereum/verkletrie/bandersnatch/fp/ElementTest.java | 2 +- .../ethereum/verkletrie/bandersnatch/fr/ElementTest.java | 2 +- 19 files changed, 26 insertions(+), 37 deletions(-) diff --git a/ethereum/retesteth/build.gradle b/ethereum/retesteth/build.gradle index 5bb9b1d8559..10b978b1534 100644 --- a/ethereum/retesteth/build.gradle +++ b/ethereum/retesteth/build.gradle @@ -50,10 +50,7 @@ dependencies { 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/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 93559791ad1..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 @@ -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); 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 17303480e92..682d26761bf 100644 --- a/ethereum/rlp/build.gradle +++ b/ethereum/rlp/build.gradle @@ -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/trie/build.gradle b/ethereum/trie/build.gradle index 99f44680d92..e8ce5cb9b70 100644 --- a/ethereum/trie/build.gradle +++ b/ethereum/trie/build.gradle @@ -45,11 +45,9 @@ dependencies { testImplementation project(':testutil') testImplementation 'com.fasterxml.jackson.core:jackson-databind' - testImplementation 'junit:junit' 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 642318e25c7..166b02efe17 100644 --- a/ethereum/verkletrie/build.gradle +++ b/ethereum/verkletrie/build.gradle @@ -47,11 +47,8 @@ dependencies { testImplementation 'com.fasterxml.jackson.core:jackson-databind' testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' - testImplementation 'junit:junit' 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 { From 1c099e8970c4693161753d588a6f763a94ece9a4 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Wed, 26 Jul 2023 12:44:01 -0400 Subject: [PATCH 27/51] Consolidated EIP-4844 (#5724) * Implements EIP-4844. * introduces a Hardfork class to the protocol schedule system * new Engine APIs required for CL to work on 4844 * new DataGas type for tracking block cost for 4844 data * new VersionedHash type to reflect that a versioned hash is not quite a pure sha256 * incorporates wrapped jc-kzg library for KZG point evaluations * New transaction type, and domain objects for constituent parts to represent the Blobs, KZGCommitments, and Proofs used for 4844 * RLP encoders and decoders to support new transaction type * gas pricing calculators for the new type of gas * plugin-api version was changed Signed-off-by: Justin Florentine Co-authored-by: Jiri Peinlich Co-authored-by: Jason Frame Co-authored-by: garyschulte Co-authored-by: Fabio Di Fabio Co-authored-by: Sally MacFarlane Co-authored-by: Gabriel Fukushima Co-authored-by: Gabriel-Trintinalia Co-authored-by: Stefan Co-authored-by: spencer-tb * junit5 updates Signed-off-by: Justin Florentine * update t8n test Cancun gas claculator was inheriting from london, should have been shanghai. Signed-off-by: Danno Ferrin --------- Signed-off-by: Justin Florentine Signed-off-by: Danno Ferrin Co-authored-by: Jiri Peinlich Co-authored-by: Jason Frame Co-authored-by: garyschulte Co-authored-by: Fabio Di Fabio Co-authored-by: Sally MacFarlane Co-authored-by: Gabriel Fukushima Co-authored-by: Gabriel-Trintinalia Co-authored-by: Stefan Co-authored-by: spencer-tb Co-authored-by: Danno Ferrin --- .../besu/tests/acceptance/dsl/BlockUtils.java | 1 + .../ExecutionEngineEip6110AcceptanceTest.java | 2 + .../jsonrpc/engine/cancun/genesis.json | 4078 ++++++++ .../01_shanghai_prepare_payload.json | 33 + .../test-cases/02_shanghai_getPayloadV2.json | 36 + .../test-cases/03_shanghai_newPayloadV2.json | 38 + .../test-cases/04_shanghai_newPayloadV3.json | 39 + .../05_cancun_forkchoiceUpdatedV2.json | 28 + .../06_cancun_forkchoiceUpdatedV2.json | 33 + .../test-cases/07_cancun_getPayloadV3.json | 42 + .../test-cases/08_cancun_newPayloadV3.json | 39 + .../jsonrpc/engine/eip6110/genesis.json | 2 +- .../test-cases/06_eip6110_get_payload.json | 2 +- .../org/hyperledger/besu/cli/BesuCommand.java | 7 +- .../besu/services/TraceServiceImpl.java | 7 +- .../hyperledger/besu/cli/BesuCommandTest.java | 12 - .../besu/services/BesuEventsImplTest.java | 2 +- besu/src/test/resources/trusted_setup.txt | 8194 ++++++++-------- .../besu/config/GenesisConfigFile.java | 18 + .../resources/kzg-trusted-setups/mainnet.txt | 8320 ++++++++--------- .../CombinedProtocolScheduleFactory.java | 8 +- .../common/bft/BftProtocolSchedule.java | 5 +- ....java => IbftExtraDataRLPEncoderTest.java} | 2 +- .../merge/TransitionProtocolSchedule.java | 7 + .../org/hyperledger/besu/datatypes/Blob.java | 64 + .../besu/datatypes/BlobsWithCommitments.java | 88 + .../hyperledger/besu/datatypes/DataGas.java | 20 +- .../org/hyperledger/besu/datatypes/Hash.java | 7 +- .../besu/datatypes/KZGCommitment.java | 63 + .../hyperledger/besu/datatypes/KZGProof.java | 63 + .../besu/datatypes/Sha256Hash.java | 42 + .../besu/datatypes/TransactionType.java | 5 +- .../besu/datatypes/VersionedHash.java | 107 + .../datatypes/BlobsWithCommitmentsTest.java | 40 + .../besu/datatypes/VersionedHashTest.java | 34 + .../api/jsonrpc/JsonRpcResponseUtils.java | 6 +- .../pojoadapter/TransactionAdapter.java | 12 +- .../besu/ethereum/api/jsonrpc/RpcMethod.java | 2 + .../api/jsonrpc/internal/JsonRpcRequest.java | 5 + .../internal/JsonRpcRequestContext.java | 5 + .../methods/EthGetMinerDataByBlockHash.java | 3 +- .../methods/EthGetTransactionReceipt.java | 9 +- .../methods/ExecuteTransactionStep.java | 8 +- .../engine/AbstractEngineNewPayload.java | 150 +- .../methods/engine/EngineGetPayloadV3.java | 91 + .../methods/engine/EngineNewPayloadV1.java | 19 + .../methods/engine/EngineNewPayloadV2.java | 19 + .../methods/engine/EngineNewPayloadV3.java | 65 + .../parameters/EnginePayloadParameter.java | 21 + .../internal/parameters/JsonRpcParameter.java | 24 + .../parameters/UnsignedLongParameter.java | 1 + .../internal/processor/BlockReplay.java | 10 +- .../internal/processor/TransactionTracer.java | 5 +- .../internal/results/BlobsBundleV1.java | 97 + .../jsonrpc/internal/results/BlockResult.java | 16 + .../internal/results/BlockResultFactory.java | 20 + .../results/EngineGetPayloadResultV3.java | 202 + .../jsonrpc/internal/results/Quantity.java | 7 +- .../results/TransactionCompleteResult.java | 24 +- .../results/TransactionPendingResult.java | 12 +- .../results/TransactionReceiptResult.java | 21 +- .../methods/ApiGroupJsonRpcMethods.java | 5 + .../jsonrpc/methods/EthJsonRpcMethods.java | 2 +- .../ExecutionEngineJsonRpcMethods.java | 125 +- .../ethereum/api/query/BlockchainQueries.java | 54 +- .../query/TransactionReceiptWithMetadata.java | 24 +- .../internal/methods/EthGasPriceTest.java | 2 + .../methods/EthGetTransactionReceiptTest.java | 121 +- .../engine/AbstractEngineGetPayloadTest.java | 30 +- .../engine/AbstractEngineNewPayloadTest.java | 265 +- ...neExchangeTransitionConfigurationTest.java | 1 + .../engine/EngineGetPayloadV3Test.java | 169 + .../engine/EngineNewPayloadEIP6110Test.java | 180 + .../engine/EngineNewPayloadV1Test.java | 17 +- .../engine/EngineNewPayloadV2Test.java | 119 +- .../engine/EngineNewPayloadV3Test.java | 119 + .../processor/TransactionTracerTest.java | 7 + .../internal/results/BlobsBundleV1Test.java | 40 + .../query/BlockchainQueriesLogCacheTest.java | 1 + .../cache/TransactionLogBloomCacherTest.java | 2 + .../blockcreation/AbstractBlockCreator.java | 35 +- .../AbstractBlockCreatorTest.java | 56 + ethereum/core/build.gradle | 2 + .../besu/ethereum/GasLimitCalculator.java | 4 +- .../besu/ethereum/chain/GenesisState.java | 35 +- .../hyperledger/besu/ethereum/core/Block.java | 16 +- .../besu/ethereum/core/BlockHeader.java | 21 +- .../ethereum/core/BlockHeaderBuilder.java | 12 + .../ethereum/core/ProcessableBlockHeader.java | 9 + .../ethereum/core/SealableBlockHeader.java | 2 + .../besu/ethereum/core/Transaction.java | 143 +- .../core/encoding/BlobTransactionDecoder.java | 108 + .../core/encoding/BlobTransactionEncoder.java | 87 + .../core/encoding/TransactionDecoder.java | 4 +- .../core/encoding/TransactionEncoder.java | 12 +- .../feemarket/TransactionPriceCalculator.java | 36 +- .../mainnet/AbstractBlockProcessor.java | 24 +- .../CancunTargetingGasLimitCalculator.java | 2 +- .../mainnet/DefaultProtocolSchedule.java | 28 +- .../mainnet/MainnetBlockHeaderValidator.java | 7 + .../mainnet/MainnetProtocolSpecs.java | 1 + .../mainnet/MainnetTransactionProcessor.java | 25 +- .../mainnet/MainnetTransactionValidator.java | 139 +- .../ethereum/mainnet/ProtocolSchedule.java | 5 + .../mainnet/ScheduledProtocolSpec.java | 26 +- .../mainnet/feemarket/CancunFeeMarket.java | 4 +- .../feemarket/ExcessDataGasCalculator.java | 42 + .../ethereum/mainnet/feemarket/FeeMarket.java | 2 +- .../mainnet/feemarket/LondonFeeMarket.java | 9 +- .../DataGasValidationRule.java | 58 + .../transaction/TransactionInvalidReason.java | 2 +- .../transaction/TransactionSimulator.java | 8 +- .../besu/ethereum/core/BlobTestFixture.java | 102 + .../ethereum/core/BlockDataGenerator.java | 3 +- .../ethereum/core/BlockHeaderTestFixture.java | 15 + .../MilestoneStreamingProtocolSchedule.java | 4 +- .../ethereum/core/NonBesuBlockHeader.java | 5 + .../ethereum/core/TransactionTestFixture.java | 29 +- .../besu/ethereum/bonsai/LogRollingTests.java | 2 + .../ethereum/core/TransactionBuilderTest.java | 9 +- .../encoding/BlobTransactionEncodingTest.java | 113 + ...st.java => TransactionRLPDecoderTest.java} | 2 +- ...st.java => TransactionRLPEncoderTest.java} | 2 +- .../ethereum/mainnet/BodyValidationTest.java | 4 +- .../MainnetTransactionValidatorTest.java | 72 +- .../feemarket/CancunFeeMarketTest.java | 67 + .../feemarket/ZeroBaseFeeMarketTest.java | 2 +- .../DataGasValidationRuleTest.java | 78 + .../core/encoding/BlobDataFixture.bin | 3911 ++++++++ .../besu/ethereum/core/encoding/blob1.txt | 1 + .../blob_transactions_test_vectors.json | 58 + .../besu/ethereum/mainnet/block_62717.blocks | Bin 0 -> 1807 bytes .../besu/ethereum/mainnet/block_62718.blocks | Bin 0 -> 1807 bytes .../messages/PooledTransactionsMessage.java | 12 +- .../eth/messages/MessageWrapperTest.java | 2 + .../backwardsync/ChainForTestCreator.java | 3 + .../besu/evmtool/StateTestSubCommand.java | 2 +- .../hyperledger/besu/evmtool/T8nExecutor.java | 17 +- .../cancun-6780-selfdestruct-transient.json | 14 +- .../besu/evmtool/t8n/cancun-blobs-per-tx.json | 29 +- .../discovery/VertxPeerDiscoveryAgent.java | 6 +- .../BlockchainReferenceTestCaseSpec.java | 2 + .../referencetests/ReferenceTestEnv.java | 4 +- .../vm/GeneralStateReferenceTestTools.java | 2 +- .../NoRewardProtocolScheduleWrapper.java | 6 + .../retesteth/methods/TestGetLogHash.java | 4 +- .../besu/evm/frame/MessageFrame.java | 12 +- .../gascalculator/CancunGasCalculator.java | 57 +- .../besu/evm/gascalculator/GasCalculator.java | 11 + .../gascalculator/LondonGasCalculator.java | 14 + .../gascalculator/ShanghaiGasCalculator.java | 14 + .../evm/operation/AbstractCallOperation.java | 1 + .../operation/AbstractCreateOperation.java | 39 +- .../besu/evm/operation/DataHashOperation.java | 21 +- .../KZGPointEvalPrecompiledContract.java | 45 +- .../CancunGasCalculatorTest.java | 46 + .../evm/operations/DataHashOperationTest.java | 37 +- .../KZGPointEvalPrecompileContractTest.java | 11 +- .../precompile/pointEvaluationPrecompile.json | 159 +- .../evm/precompile/trusted_setup_4096.txt | 4163 --------- .../precompile/verifyAggregateKzgProof.json | 6 + gradle/verification-metadata.xml | 14 +- gradle/versions.gradle | 2 +- plugin-api/build.gradle | 4 +- .../besu/plugin/data/BlockHeader.java | 8 + 165 files changed, 20679 insertions(+), 13156 deletions(-) create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/01_shanghai_prepare_payload.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/02_shanghai_getPayloadV2.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/03_shanghai_newPayloadV2.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/04_shanghai_newPayloadV3.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/05_cancun_forkchoiceUpdatedV2.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/06_cancun_forkchoiceUpdatedV2.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/07_cancun_getPayloadV3.json create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/08_cancun_newPayloadV3.json rename consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/{IbftExtraDataEncoderTest.java => IbftExtraDataRLPEncoderTest.java} (99%) create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobsWithCommitments.java create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGProof.java create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/Sha256Hash.java create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java create mode 100644 datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java create mode 100644 datatypes/src/test/java/org/hyperledger/besu/datatypes/VersionedHashTest.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110Test.java create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1Test.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessDataGasCalculator.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRule.java create mode 100644 ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java rename ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/{TransactionDecoderTest.java => TransactionRLPDecoderTest.java} (99%) rename ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/{TransactionEncoderTest.java => TransactionRLPEncoderTest.java} (99%) create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarketTest.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRuleTest.java create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/BlobDataFixture.bin create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob1.txt create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/core/encoding/blob_transactions_test_vectors.json create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62717.blocks create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/mainnet/block_62718.blocks create mode 100644 evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java delete mode 100644 evm/src/test/resources/org/hyperledger/besu/evm/precompile/trusted_setup_4096.txt create mode 100644 evm/src/test/resources/org/hyperledger/besu/evm/precompile/verifyAggregateKzgProof.json 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/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/resources/jsonrpc/engine/cancun/genesis.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json new file mode 100644 index 00000000000..b23dab36078 --- /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, + "dataGasUsed": null, + "excessDataGas": 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..57ecc2c349c --- /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": [], + "dataGasUsed": null, + "excessDataGas": 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..dd468532406 --- /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": [], + "dataGasUsed": null, + "excessDataGas": 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..47be6015333 --- /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", + "excessDataGas": "0x0", + "transactions": [], + "withdrawals": [], + "blockNumber": "0x2", + "dataGasUsed": "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..b3ed245ba19 --- /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": [], + "dataGasUsed": "0x0", + "excessDataGas": "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/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 182b8f762aa..31c72c86411 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1562,6 +1562,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); } } @@ -1875,12 +1876,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 { 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 aa8cc6b71bd..4a5e6f513f2 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TraceServiceImpl.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.services; import static com.google.common.base.Preconditions.checkArgument; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; @@ -113,9 +114,11 @@ private void trace(final Block block, final BlockAwareOperationTracer tracer) { final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .dataPricePerGas( maybeParentHeader - .flatMap(BlockHeader::getExcessDataGas) + .map( + parent -> + calculateExcessDataGasForParent(protocolSpec, parent)) .orElse(DataGas.ZERO)); tracer.traceStartTransaction(transaction); 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 7f78c5d85b3..9a4fcc0fdda 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -5663,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/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index dec24832a69..281cb2b2ea1 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -200,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/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/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java index 73d7174303e..9b706ab1a38 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 data gas. + * + * @return the excess data gas + */ + public String getExcessDataGas() { + return JsonUtil.getValueAsString(configRoot, "excessdatagas", "0x0"); + } + + /** + * Gets data gas used. + * + * @return the data gas used + */ + public String getDataGasUsed() { + return JsonUtil.getValueAsString(configRoot, "datagasused", "0x0"); + } + /** * Gets coinbase. * 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/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/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/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 82fdd8e3438..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 @@ -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. * 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/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 index 6028403ed0e..197edc29cfd 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java @@ -17,11 +17,11 @@ import java.math.BigInteger; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.units.bigints.BaseUInt256Value; -import org.apache.tuweni.units.bigints.UInt256; +import org.apache.tuweni.units.bigints.BaseUInt64Value; +import org.apache.tuweni.units.bigints.UInt64; /** A particular quantity of DataGas */ -public final class DataGas extends BaseUInt256Value implements Quantity { +public final class DataGas extends BaseUInt64Value implements Quantity { /** The constant ZERO. */ public static final DataGas ZERO = of(0); @@ -30,27 +30,27 @@ public final class DataGas extends BaseUInt256Value implements Quantity public static final DataGas ONE = of(1); /** The constant MAX_DATA_GAS. */ - public static final DataGas MAX_DATA_GAS = of(UInt256.MAX_VALUE); + public static final DataGas MAX_DATA_GAS = of(UInt64.MAX_VALUE); /** * Instantiates a new DataGas. * * @param value the value */ - DataGas(final UInt256 value) { + DataGas(final UInt64 value) { super(value, DataGas::new); } private DataGas(final long v) { - this(UInt256.valueOf(v)); + this(UInt64.valueOf(v)); } private DataGas(final BigInteger v) { - this(UInt256.valueOf(v)); + this(UInt64.valueOf(v)); } private DataGas(final String hexString) { - this(UInt256.fromHexString(hexString)); + this(UInt64.fromHexString(hexString)); } /** @@ -79,7 +79,7 @@ public static DataGas of(final BigInteger value) { * @param value the value * @return the data gas */ - public static DataGas of(final UInt256 value) { + public static DataGas of(final UInt64 value) { return new DataGas(value); } @@ -100,7 +100,7 @@ public static DataGas ofNumber(final Number value) { * @return the data gas */ public static DataGas wrap(final Bytes value) { - return new DataGas(UInt256.fromBytes(value)); + return new DataGas(UInt64.fromBytes(value)); } /** 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/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java index 26c94994c64..b100240058c 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java @@ -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..97cb093f4d8 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.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.datatypes; + +import java.util.Objects; + +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 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; + } + + /** + * 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/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 3f87d924a9d..9c0a7490240 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 @@ -127,6 +127,7 @@ public JsonRpcResponse response( mixHash, nonce, withdrawalsRoot, + null, // ToDo 4844: set with the value of data_gas_used field null, // ToDo 4844: set with the value of excess_data_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/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/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index 9c7871b6a27..18fe0d87ac5 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 @@ -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"), 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/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/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/ExecuteTransactionStep.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecuteTransactionStep.java index e88f0e85b9f..99b157c2205 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,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; + import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; @@ -89,8 +91,10 @@ public TransactionTrace apply(final TransactionTrace transactionTrace) { final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice( - maybeParentHeader.flatMap(BlockHeader::getExcessDataGas).orElse(DataGas.ZERO)); + .dataPricePerGas( + maybeParentHeader + .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) + .orElse(DataGas.ZERO)); final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(header, blockchain); result = transactionProcessor.processTransaction( 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 807b1387a73..8215eae8be3 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 @@ -25,7 +25,9 @@ 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.DataGas; 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; @@ -52,10 +54,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.ExcessDataGasCalculator; 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 +71,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,13 +104,32 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) final EnginePayloadParameter blockParam = requestContext.getRequiredParameter(0, EnginePayloadParameter.class); + Optional> maybeVersionedHashParam = + requestContext.getOptionalList(1, String.class); + Object reqId = requestContext.getRequest().getId(); + 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: {}") .addArgument(() -> Json.encodePrettily(blockParam)) .log(); + /* + ValidationResult forkValidationResult = validateForkSupported(reqId, blockParam); + if (!forkValidationResult.isValid()) { + return new JsonRpcErrorResponse(reqId, forkValidationResult.getInvalidReason()); + } + */ + final Optional> maybeWithdrawals = Optional.ofNullable(blockParam.getWithdrawals()) .map(ws -> ws.stream().map(WithdrawalParameter::toWithdrawal).collect(toList())); @@ -172,7 +198,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) blockParam.getPrevRandao(), 0, maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null), - null, + blockParam.getDataGasUsed() == null ? null : blockParam.getDataGasUsed(), + blockParam.getExcessDataGas() == null + ? null + : DataGas.fromHexString(blockParam.getExcessDataGas()), maybeDeposits.map(BodyValidation::depositsRoot).orElse(null), headerFunctions); @@ -184,8 +213,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 +253,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 +274,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .addArgument(block::toLogString) .log(); mergeCoordinator.appendNewPayloadToSync(block); - return respondWith(reqId, blockParam, null, SYNCING); } @@ -341,6 +389,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 excessDataGas + if (maybeParentHeader.isPresent()) { + if (!validateExcessDataGas(header, maybeParentHeader.get(), protocolSpec)) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, + "Payload excessDataGas does not match calculated excessDataGas"); + } + } + + // Validate dataGasUsed + if (header.getDataGasUsed().isPresent() && maybeVersionedHashes.isPresent()) { + if (!validateDataGasUsed(header, maybeVersionedHashes.get(), protocolSpec)) { + return ValidationResult.invalid( + RpcErrorType.INVALID_PARAMS, + "Payload DataGasUsed does not match calculated DataGasUsed"); + } + } + return ValidationResult.valid(); + } + + private boolean validateExcessDataGas( + final BlockHeader header, final BlockHeader parentHeader, final ProtocolSpec protocolSpec) { + DataGas calculatedDataGas = + ExcessDataGasCalculator.calculateExcessDataGasForParent(protocolSpec, parentHeader); + return header.getExcessDataGas().orElse(DataGas.ZERO).equals(calculatedDataGas); + } + + private boolean validateDataGasUsed( + final BlockHeader header, + final List maybeVersionedHashes, + final ProtocolSpec protocolSpec) { + var calculatedDataGas = + protocolSpec.getGasCalculator().dataGasCost(maybeVersionedHashes.size()); + return header.getDataGasUsed().orElse(0L).equals(calculatedDataGas); + } + + 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/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..6454c22fdb6 --- /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.getDataGasUsed() == null + || payloadParameter.getExcessDataGas() == null) { + return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing data gas fields"); + } else { + return ValidationResult.valid(); + } + } else { + return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Fork not supported"); + } + } +} 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..a643c4d1dba 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 dataGasUsed; + private final String excessDataGas; + 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("dataGasUsed") final UnsignedLongParameter dataGasUsed, + @JsonProperty("excessDataGas") final String excessDataGas, + @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.dataGasUsed = dataGasUsed == null ? null : dataGasUsed.getValue(); + this.excessDataGas = excessDataGas; + this.versionedHashes = versionedHashes; this.deposits = deposits; } @@ -145,7 +154,19 @@ public List getWithdrawals() { return withdrawals; } + public Long getDataGasUsed() { + return dataGasUsed; + } + + public String getExcessDataGas() { + return excessDataGas; + } + 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/processor/BlockReplay.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java index 252771a7ed9..49fe92cf604 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,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; + import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -52,10 +54,10 @@ public Optional block( final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .dataPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) + .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) .orElse(DataGas.ZERO)); final List transactionTraces = @@ -86,10 +88,10 @@ public Optional beforeTransactionInBlock( final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .dataPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) + .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) .orElse(DataGas.ZERO)); for (final Transaction transaction : body.getTransactions()) { 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..141321a9b18 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,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor; import static java.util.function.Predicate.isEqual; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; @@ -118,10 +119,10 @@ public List traceTransactionToFile( final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice( + .dataPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) + .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) .orElse(DataGas.ZERO)); for (int i = 0; i < body.getTransactions().size(); i++) { ((StackedUpdater) stackedUpdater).markTransactionBoundary(); 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..9cc1f4e2cd9 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 dataGasUsed; + private final String excessDataGas; + 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.dataGasUsed = header.getDataGasUsed().map(Quantity::create).orElse(null); + this.excessDataGas = header.getExcessDataGas().map(Quantity::create).orElse(null); } @JsonGetter(value = "number") @@ -250,4 +256,14 @@ public String getWithdrawalsRoot() { public List getWithdrawals() { return withdrawals; } + + @JsonGetter(value = "dataGasUsed") + public String getDataGasUsed() { + return dataGasUsed; + } + + @JsonGetter(value = "excessDataGas") + public String getExcessDataGas() { + return excessDataGas; + } } 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..f499e6da868 --- /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 excessDataGas; + + private final String dataGasUsed; + + 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.dataGasUsed = header.getDataGasUsed().map(Quantity::create).orElse(Quantity.HEX_ZERO); + this.excessDataGas = + header.getExcessDataGas().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 = "excessDataGas") + public String getExcessDataGas() { + return excessDataGas; + } + + @JsonGetter(value = "dataGasUsed") + public String getDataGasUseds() { + return dataGasUsed; + } + } +} 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 44d9b69f6d6..3cbc5c40309 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 @@ -15,6 +15,7 @@ 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; @@ -37,6 +38,7 @@ "gasPrice", "maxPriorityFeePerGas", "maxFeePerGas", + "maxFeePerDataGas", "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 maxFeePerDataGas; + 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.maxFeePerDataGas = + transaction.getMaxFeePerDataGas().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 = "maxFeePerDataGas") + public String getMaxFeePerDataGas() { + return maxFeePerDataGas; + } + @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 4f79320ecf2..1b98c88c946 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,11 +15,11 @@ 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 java.util.List; @@ -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(); @@ -99,9 +99,7 @@ public TransactionPendingResult(final Transaction transaction) { 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) @@ -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 701f8e3064b..ea233098197 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 @@ -46,7 +46,9 @@ "transactionHash", "transactionIndex", "revertReason", - "type" + "type", + "dataGasUsed", + "dataGasPrice" }) public abstract class TransactionReceiptResult { @@ -67,6 +69,9 @@ public abstract class TransactionReceiptResult { protected final TransactionReceipt receipt; protected final String type; + private final String dataGasUsed; + private final String dataGasPrice; + 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.dataGasUsed = receiptWithMetadata.getDataGasUsed().map(Quantity::create).orElse(null); + this.dataGasPrice = receiptWithMetadata.getDataGasPrice().map(Quantity::create).orElse(null); this.effectiveGasPrice = Quantity.create(txn.getEffectiveGasPrice(receiptWithMetadata.getBaseFee())); @@ -127,6 +134,18 @@ public String getGasUsed() { return gasUsed; } + @JsonGetter(value = "dataGasUsed") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getDataGasUsed() { + return dataGasUsed; + } + + @JsonGetter(value = "dataGasPrice") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getDataGasPrice() { + return dataGasPrice; + } + @JsonGetter(value = "effectiveGasPrice") public String getEffectiveGasPrice() { return effectiveGasPrice; 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/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java index 55d2a8fb9c9..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 @@ -142,7 +142,7 @@ protected Map create() { new EthGetTransactionByBlockHashAndIndex(blockchainQueries), new EthGetTransactionByBlockNumberAndIndex(blockchainQueries), new EthGetTransactionCount(blockchainQueries, transactionPool), - new EthGetTransactionReceipt(blockchainQueries), + 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/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 96e01fdb1b2..4e8aea3fe73 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.ExcessDataGasCalculator.calculateExcessDataGasForParent; 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 maybeDataGasUsed = + getDataGasUsed(transaction, protocolSchedule.getByBlockHeader(header)); + + Optional maybeDataGasPrice = + getDataGasPrice(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(), + maybeDataGasUsed, + maybeDataGasPrice)); + } + + /** + * Calculates the data 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 data gas used for data if the transaction type supports + * blobs, otherwise returns an empty Optional + */ + private Optional getDataGasUsed( + final Transaction transaction, final ProtocolSpec protocolSpec) { + return transaction.getType().supportsBlob() + ? Optional.of(protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount())) + : Optional.empty(); + } + + /** + * Calculates the data 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 data gas price for data if the transaction type supports + * blobs, otherwise returns an empty Optional + */ + private Optional getDataGasPrice( + final Transaction transaction, final BlockHeader header, final ProtocolSpec protocolSpec) { + if (transaction.getType().supportsBlob()) { + return blockchain + .getBlockHeader(header.getParentHash()) + .map( + parentHeader -> + protocolSpec + .getFeeMarket() + .dataPricePerGas( + calculateExcessDataGasForParent(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..77a910cfc1b 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 dataGasUsed; + private final Optional dataGasPrice; 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 dataGasUsed, + final Optional dataGasPrice) { 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.dataGasUsed = dataGasUsed; + this.dataGasPrice = dataGasPrice; } 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 dataGasUsed, + final Optional dataGasPrice) { return new TransactionReceiptWithMetadata( receipt, transaction, @@ -67,7 +75,9 @@ public static TransactionReceiptWithMetadata create( gasUsed, baseFee, blockHash, - blockNumber); + blockNumber, + dataGasUsed, + dataGasPrice); } public TransactionReceipt getReceipt() { @@ -103,4 +113,12 @@ public long getGasUsed() { public Optional getBaseFee() { return baseFee; } + + public Optional getDataGasUsed() { + return dataGasUsed; + } + + public Optional getDataGasPrice() { + return dataGasPrice; + } } 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 7ecf082759b..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 @@ -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/EthGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java index 565c58191c5..649b0cae084 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,12 +15,15 @@ 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.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; @@ -32,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; @@ -40,13 +47,18 @@ 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.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.jupiter.api.Test; @@ -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( @@ -151,9 +181,12 @@ public class EthGetTransactionReceiptTest { @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 = @@ -164,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); @@ -180,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); @@ -195,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); @@ -220,6 +262,63 @@ public void shouldWorkFor1559Txs() { transaction1559.getMaxFeePerGas().get())); } + /** + * Test case to verify that the TransactionReceiptStatusResult contains data gas used and data gas + * price when the transaction type is TransactionType#BLOB + */ + @Test + public void shouldContainDataGasUsedAndDataGasPriceWhenBlobTransaction() { + + 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.getDataGasUsed()).isEqualTo("0x20000"); + assertThat(result.getDataGasPrice()).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.getExcessDataGas()).thenReturn(Optional.of(DataGas.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.dataPricePerGas(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/engine/AbstractEngineGetPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java index 0b902f8b13a..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,10 +39,14 @@ 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.jupiter.api.BeforeEach; @@ -51,6 +59,10 @@ @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; + @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 4ff38931cb3..aaaef981fcc 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,8 @@ 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.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.never; import static org.mockito.Mockito.spy; @@ -32,13 +30,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.DataGas; 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; @@ -75,9 +73,7 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; -import org.jetbrains.annotations.NotNull; 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; @@ -87,6 +83,12 @@ @ExtendWith(MockitoExtension.class) public abstract class AbstractEngineNewPayloadTest { + protected final long LONDON_TIMESTAMP = 0; + protected final long PARIS_TIMESTAMP = 10; + protected final long SHANGHAI_TIMESTAMP = 20; + protected final long CANCUN_TIMESTAMP = 30; + protected final long EXPERIMENTAL_TIMESTAMP = 40; + @FunctionalInterface interface MethodFactory { AbstractEngineNewPayload create( @@ -98,29 +100,25 @@ AbstractEngineNewPayload create( final EngineCallListener engineCallListener); } - private final MethodFactory methodFactory; + // private final MethodFactory methodFactory; protected AbstractEngineNewPayload method; - public AbstractEngineNewPayloadTest(final MethodFactory methodFactory) { - this.methodFactory = methodFactory; - } + 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 ProtocolSchedule 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; @@ -128,20 +126,14 @@ public AbstractEngineNewPayloadTest(final MethodFactory methodFactory) { 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); } @Test @@ -184,7 +176,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); } @@ -269,7 +262,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")); @@ -285,7 +279,9 @@ public void shouldNotReturnInvalidOnThrownMerkleTrieException() { @Test public void shouldReturnInvalidBlockHashOnBadHashParameter() { BlockHeader mockHeader = new BlockHeaderTestFixture().buildHeader(); - + lenient() + .when(mergeCoordinator.getLatestValidAncestor(mockHeader.getBlockHash())) + .thenReturn(Optional.empty()); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); @@ -372,14 +368,6 @@ public void shouldRespondWithSyncingDuringBackwardsSync() { verify(engineCallListener, times(1)).executionEngineCalled(); } - @Test - @Disabled - 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(); @@ -409,146 +397,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); @@ -566,35 +414,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,14 +456,17 @@ private EnginePayloadParameter mockPayload( header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), txs, withdrawals, + header.getDataGasUsed().map(UnsignedLongParameter::new).orElse(null), + header.getExcessDataGas().map(DataGas::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())) @@ -626,7 +474,8 @@ private BlockHeader setupValidPayload( 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 +499,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 +524,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/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index 2aabfa68436..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 @@ -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/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..6d2f432f726 --- /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.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.DataGas; +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) + .excessDataGas(DataGas.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))) + .maxFeePerDataGas(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("")); + // excessDataGas: QUANTITY, 256 bits + String expectedQuantityOf10 = Bytes32.leftPad(Bytes.of(10)).toQuantityHexString(); + assertThat(res.getExecutionPayload().getExcessDataGas()).isNotEmpty(); + assertThat(res.getExecutionPayload().getExcessDataGas()) + .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..aec754b484e --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110Test.java @@ -0,0 +1,180 @@ +/* + * 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.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; +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.ethereum.mainnet.ScheduledProtocolSpec; +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(new ScheduledProtocolSpec.Hardfork("Cancun", super.CANCUN_TIMESTAMP))); + 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()); + + 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)); + + 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.EXPERIMENTAL_TIMESTAMP) + .excessDataGas(DataGas.ZERO) + .dataGasUsed(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)) + .excessDataGas(DataGas.ZERO) + .dataGasUsed(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 b7bf31f7ee5..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,6 +32,7 @@ import java.util.Collections; 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; @@ -42,8 +43,20 @@ @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 2679a386410..314e3a17cea 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,7 +15,28 @@ 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.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +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; + +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; @@ -26,8 +47,20 @@ @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 @@ -35,4 +68,86 @@ 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()); + + 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()); + + 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..17f34a03480 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -0,0 +1,119 @@ +/* + * 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.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; + +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.ethereum.mainnet.ScheduledProtocolSpec; +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()); + lenient() + .when(protocolSchedule.hardforkFor(any())) + .thenReturn( + Optional.of(new ScheduledProtocolSpec.Hardfork("Cancun", super.CANCUN_TIMESTAMP))); + } + + @Test + public void shouldInvalidPayloadOnShortVersionedHash() { + Bytes shortHash = Bytes.fromHexString("0x" + "69".repeat(31)); + EnginePayloadParameter payload = mock(EnginePayloadParameter.class); + 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.CANCUN_TIMESTAMP) + .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)) + .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) + .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/processor/TransactionTracerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java index fd11a468e56..88266a64117 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; @@ -80,6 +84,7 @@ public class TransactionTracerTest { @Mock private DebugOperationTracer tracer; @Mock private ProtocolSpec protocolSpec; + @Mock private GasCalculator gasCalculator; @Mock private Tracer.TraceableState mutableWorldState; @@ -114,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.computeExcessDataGas(anyLong(), anyInt())).thenReturn(0L); } @Test 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/query/BlockchainQueriesLogCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java index bc9bc2afd0c..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 @@ -116,6 +116,7 @@ public void setup() { null, null, null, + null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); final BlockBody fakeBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); 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 c5442c434ed..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 @@ -108,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)); @@ -281,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/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 55f0ccc3cb7..dead80c5a46 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,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.blockcreation; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; + import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; @@ -169,10 +171,10 @@ protected BlockCreationResult createBlock( createPendingBlockHeader(timestamp, maybePrevRandao, newProtocolSpec); final Address miningBeneficiary = miningBeneficiaryCalculator.getMiningBeneficiary(processableBlockHeader.getNumber()); - final Wei dataGasPrice = + Wei dataGasPrice = newProtocolSpec .getFeeMarket() - .dataPrice(parentHeader.getExcessDataGas().orElse(DataGas.ZERO)); + .dataPricePerGas(calculateExcessDataGasForParent(newProtocolSpec, parentHeader)); throwIfStopped(); @@ -228,11 +230,11 @@ protected BlockCreationResult createBlock( throwIfStopped(); - final DataGas newExcessDataGas = computeExcessDataGas(transactionResults, newProtocolSpec); + final GasUsage usage = computeExcessDataGas(transactionResults, newProtocolSpec); throwIfStopped(); - final SealableBlockHeader sealableBlockHeader = + BlockHeaderBuilder builder = BlockHeaderBuilder.create() .populateFrom(processableBlockHeader) .ommersHash(BodyValidation.ommersHash(ommers)) @@ -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.dataGasUsed(usage.used.toLong()).excessDataGas(usage.excessDataGas); + } + + final SealableBlockHeader sealableBlockHeader = builder.buildSealableBlockHeader(); final BlockHeader blockHeader = createFinalBlockHeader(sealableBlockHeader); @@ -280,8 +285,11 @@ List findDepositsFromReceipts(final TransactionSelectionResults transac .toList(); } - private DataGas computeExcessDataGas( - TransactionSelectionResults transactionResults, ProtocolSpec newProtocolSpec) { + record GasUsage(DataGas excessDataGas, DataGas used) {} + ; + + private GasUsage computeExcessDataGas( + final TransactionSelectionResults transactionResults, final ProtocolSpec newProtocolSpec) { if (newProtocolSpec.getFeeMarket().implementsDataFee()) { final var gasCalculator = newProtocolSpec.getGasCalculator(); @@ -292,9 +300,12 @@ private DataGas computeExcessDataGas( .sum(); // casting parent excess data 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)); + DataGas ecessDataGas = + DataGas.of( + gasCalculator.computeExcessDataGas( + parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), newBlobsCount)); + DataGas used = DataGas.of(gasCalculator.dataGasCost(newBlobsCount)); + return new GasUsage(ecessDataGas, used); } return null; } 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 1bc9ff4b64e..b16cc1e9d6c 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 @@ -27,15 +27,21 @@ 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.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.DataGas; 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; @@ -45,7 +51,9 @@ 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; @@ -61,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; @@ -76,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; @@ -260,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 = blockCreatorWithDataGasSupport(); + 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))) + .maxFeePerDataGas(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 dataGasUsage = blockCreationResult.getBlock().getHeader().getGasUsed(); + assertThat(dataGasUsage).isNotZero(); + DataGas excessDataGas = blockCreationResult.getBlock().getHeader().getExcessDataGas().get(); + assertThat(excessDataGas).isNotNull(); + } + + private AbstractBlockCreator blockCreatorWithDataGasSupport() { + 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( diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 92186b04e2e..b616413dd22 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -60,6 +60,7 @@ dependencies { 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' @@ -93,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' 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..05605d6c3b8 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,6 +16,8 @@ public interface GasLimitCalculator { + static final long DATA_GAS_LIMIT = 786432; + long nextGasLimit(long currentGasLimit, long targetGasLimit, long newBlockNumber); static GasLimitCalculator constant() { @@ -23,6 +25,6 @@ static GasLimitCalculator constant() { } default long currentDataGasLimit() { - return 0L; + return DATA_GAS_LIMIT; } } 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..959559a9af5 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.DataGas; 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) + .dataGasUsed(isCancunAtGenesis(genesis) ? parseDataGasUsed(genesis) : null) + .excessDataGas(isCancunAtGenesis(genesis) ? parseExcessDataGas(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 parseDataGasUsed(final GenesisConfigFile genesis) { + return withNiceErrorMessage( + "dataGasUsed", genesis.getDataGasUsed(), GenesisState::parseUnsignedLong); + } + + private static DataGas parseExcessDataGas(final GenesisConfigFile genesis) { + long excessDataGas = + withNiceErrorMessage( + "excessDataGas", genesis.getExcessDataGas(), GenesisState::parseUnsignedLong); + return DataGas.of(excessDataGas); + } + 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..eb2e906af70 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 @@ -62,6 +62,7 @@ public BlockHeader( final Bytes32 mixHashOrPrevRandao, final long nonce, final Hash withdrawalsRoot, + final long dataGasUsed, final DataGas excessDataGas, final Hash depositsRoot, final BlockHeaderFunctions blockHeaderFunctions, @@ -83,6 +84,7 @@ public BlockHeader( baseFee, mixHashOrPrevRandao, withdrawalsRoot, + dataGasUsed, excessDataGas, depositsRoot); this.nonce = nonce; @@ -108,6 +110,7 @@ public BlockHeader( final Bytes32 mixHashOrPrevRandao, final long nonce, final Hash withdrawalsRoot, + final Long dataGasUsed, final DataGas excessDataGas, final Hash depositsRoot, final BlockHeaderFunctions blockHeaderFunctions) { @@ -128,6 +131,7 @@ public BlockHeader( baseFee, mixHashOrPrevRandao, withdrawalsRoot, + dataGasUsed, excessDataGas, depositsRoot); this.nonce = nonce; @@ -212,8 +216,9 @@ public void writeTo(final RLPOutput out) { if (withdrawalsRoot != null) { out.writeBytes(withdrawalsRoot); } - if (excessDataGas != null) { - out.writeUInt256Scalar(excessDataGas); + if (excessDataGas != null && dataGasUsed != null) { + out.writeLongScalar(dataGasUsed); + out.writeUInt64Scalar(excessDataGas); } 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; + !(input.isEndOfCurrentList() || input.isZeroLengthString()) + ? Hash.wrap(input.readBytes32()) + : null; + final Long dataGasUsed = !input.isEndOfCurrentList() ? input.readLongScalar() : null; final DataGas excessDataGas = - !input.isEndOfCurrentList() ? DataGas.of(input.readUInt256Scalar()) : null; + !input.isEndOfCurrentList() ? DataGas.of(input.readLongScalar()) : null; final Hash depositHashRoot = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null; input.leaveList(); @@ -265,6 +273,7 @@ public static BlockHeader readFrom( mixHashOrPrevRandao, nonce, withdrawalHashRoot, + dataGasUsed, excessDataGas, depositHashRoot, blockHeaderFunctions); @@ -311,6 +320,9 @@ public String toString() { if (withdrawalsRoot != null) { sb.append("withdrawalsRoot=").append(withdrawalsRoot).append(", "); } + if (dataGasUsed != null) { + sb.append("dataGasUsed=").append(dataGasUsed).append(", "); + } if (excessDataGas != null) { sb.append("excessDataGas=").append(excessDataGas).append(", "); } @@ -344,6 +356,7 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH .getWithdrawalsRoot() .map(h -> Hash.fromHexString(h.toHexString())) .orElse(null), + pluginBlockHeader.getDataGasUsed().map(Long::longValue).orElse(null), pluginBlockHeader.getExcessDataGas().map(DataGas::fromQuantity).orElse(null), pluginBlockHeader .getDepositsRoot() 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..41536ca964e 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 @@ -73,6 +73,7 @@ public class BlockHeaderBuilder { // instead of an invalid identifier such as -1. private OptionalLong nonce = OptionalLong.empty(); + private Long dataGasUsed = null; private DataGas excessDataGas = null; public static BlockHeaderBuilder create() { @@ -119,6 +120,7 @@ public static BlockHeaderBuilder fromHeader(final BlockHeader header) { .nonce(header.getNonce()) .prevRandao(header.getPrevRandao().orElse(null)) .withdrawalsRoot(header.getWithdrawalsRoot().orElse(null)) + .dataGasUsed(header.getDataGasUsed().orElse(null)) .excessDataGas(header.getExcessDataGas().orElse(null)) .depositsRoot(header.getDepositsRoot().orElse(null)); } @@ -170,6 +172,7 @@ public BlockHeader buildBlockHeader() { mixHashOrPrevRandao, nonce.getAsLong(), withdrawalsRoot, + dataGasUsed, excessDataGas, depositsRoot, blockHeaderFunctions); @@ -187,6 +190,7 @@ public ProcessableBlockHeader buildProcessableBlockHeader() { timestamp, baseFee, mixHashOrPrevRandao, + dataGasUsed, excessDataGas); } @@ -210,6 +214,7 @@ public SealableBlockHeader buildSealableBlockHeader() { baseFee, mixHashOrPrevRandao, withdrawalsRoot, + dataGasUsed, excessDataGas, depositsRoot); } @@ -251,6 +256,7 @@ public BlockHeaderBuilder populateFrom(final ProcessableBlockHeader processableB timestamp(processableBlockHeader.getTimestamp()); baseFee(processableBlockHeader.getBaseFee().orElse(null)); processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); + processableBlockHeader.getDataGasUsed().ifPresent(this::dataGasUsed); processableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); return this; } @@ -273,6 +279,7 @@ public BlockHeaderBuilder populateFrom(final SealableBlockHeader sealableBlockHe baseFee(sealableBlockHeader.getBaseFee().orElse(null)); sealableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); withdrawalsRoot(sealableBlockHeader.getWithdrawalsRoot().orElse(null)); + sealableBlockHeader.getDataGasUsed().ifPresent(this::dataGasUsed); sealableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); depositsRoot(sealableBlockHeader.getDepositsRoot().orElse(null)); return this; @@ -399,4 +406,9 @@ public BlockHeaderBuilder excessDataGas(final DataGas excessDataGas) { this.excessDataGas = excessDataGas; return this; } + + public BlockHeaderBuilder dataGasUsed(final Long dataGasUsed) { + this.dataGasUsed = dataGasUsed; + return this; + } } 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..716782c047c 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 @@ -44,6 +44,9 @@ public class ProcessableBlockHeader implements BlockValues { protected final Wei baseFee; // prevRandao is included for post-merge blocks protected final Bytes32 mixHashOrPrevRandao; + // dataGasUsed is included for Cancun + protected final Long dataGasUsed; + // excessDataGas is included for Cancun protected final DataGas excessDataGas; protected ProcessableBlockHeader( @@ -55,6 +58,7 @@ protected ProcessableBlockHeader( final long timestamp, final Wei baseFee, final Bytes32 mixHashOrPrevRandao, + final Long dataGasUsed, final DataGas excessDataGas) { this.parentHash = parentHash; this.coinbase = coinbase; @@ -64,6 +68,7 @@ protected ProcessableBlockHeader( this.timestamp = timestamp; this.baseFee = baseFee; this.mixHashOrPrevRandao = mixHashOrPrevRandao; + this.dataGasUsed = dataGasUsed; this.excessDataGas = excessDataGas; } @@ -167,6 +172,10 @@ public Optional getExcessDataGas() { return Optional.ofNullable(excessDataGas); } + public Optional getDataGasUsed() { + return Optional.ofNullable(dataGasUsed); + } + public String toLogString() { return getNumber() + " (time: " + getTimestamp() + ")"; } 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..8b76768eb7e 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 @@ -62,6 +62,7 @@ protected SealableBlockHeader( final Wei baseFee, final Bytes32 mixHashOrPrevRandao, final Hash withdrawalsRoot, + final Long dataGasUsed, final DataGas excessDataGas, final Hash depositsRoot) { super( @@ -73,6 +74,7 @@ protected SealableBlockHeader( timestamp, baseFee, mixHashOrPrevRandao, + dataGasUsed, excessDataGas); this.ommersHash = ommersHash; this.stateRoot = stateRoot; 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 3d381ae62b0..84228559606 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,10 +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; @@ -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(); @@ -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( @@ -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"); @@ -226,7 +238,8 @@ public Transaction( final Bytes payload, final Address sender, final Optional chainId, - final Optional> versionedHashes) { + final Optional> versionedHashes, + final Optional blobsWithCommitments) { this( TransactionType.FRONTIER, nonce, @@ -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 maxFeePerDataGas, + final Optional> versionedHashes, + final Optional blobsWithCommitments) { + this( + nonce, + Optional.of(gasPrice), + Optional.empty(), + Optional.empty(), + maxFeePerDataGas, + gasLimit, + to, + value, + signature, + payload, + sender, + chainId, + versionedHashes, + blobsWithCommitments); } /** @@ -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(); + } } /** @@ -731,8 +801,12 @@ public TransactionType getType() { return this.transactionType; } - public Optional> getVersionedHashes() { - return this.versionedHashes; + public Optional> getVersionedHashes() { + return versionedHashes; + } + + public Optional getBlobsWithCommitments() { + return blobsWithCommitments; } /** @@ -758,7 +832,7 @@ private static Bytes32 computeSenderRecoveryHash( 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); @@ -907,7 +981,8 @@ private static Bytes blobPreimage( final Bytes payload, final Optional chainId, final Optional> accessList, - final List versionedHashes) { + final List versionedHashes) { + final Bytes encoded = RLP.encode( rlpOutput -> { @@ -924,7 +999,7 @@ private static Bytes blobPreimage( accessList, rlpOutput); rlpOutput.writeUInt256Scalar(maxFeePerDataGas); - TransactionEncoder.writeBlobVersionedHashes(rlpOutput, versionedHashes); + BlobTransactionEncoder.writeBlobVersionedHashes(rlpOutput, versionedHashes); rlpOutput.endList(); }); return Bytes.concatenate(Bytes.of(TransactionType.BLOB.getSerializedType()), encoded); @@ -989,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() @@ -1021,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(", "); @@ -1080,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; @@ -1162,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; } @@ -1201,7 +1284,8 @@ public Transaction build() { accessList, sender, chainId, - Optional.ofNullable(versionedHashes)); + Optional.ofNullable(versionedHashes), + Optional.ofNullable(blobsWithCommitments)); } public Transaction signAndBuild(final KeyPair keys) { @@ -1231,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.hash(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/encoding/BlobTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionDecoder.java new file mode 100644 index 00000000000..d9dd82b567c --- /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; + })) + .maxFeePerDataGas(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..63ee8fbb8a8 --- /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.getMaxFeePerDataGas().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 e3ba2dc4736..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 @@ -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 f511a917a91..4a0f1f02257 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,7 +17,6 @@ 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; @@ -44,7 +43,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 = @@ -185,17 +186,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..aad41dd9fea 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.DataGas; 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 dataGas( + final int minDataGasPrice, + final int dataGasPriceUpdateFraction, + final DataGas excessDataGas) { + return ((transaction, baseFee) -> { + final var dataGasPrice = + Wei.of( + fakeExponential( + BigInteger.valueOf(minDataGasPrice), + excessDataGas.toBigInteger(), + BigInteger.valueOf(dataGasPriceUpdateFraction))); + return dataGasPrice; + }); + } } 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 3a18429aba0..15aca473829 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,9 @@ */ package org.hyperledger.besu.ethereum.mainnet; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; + 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; @@ -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 dataGasPrice = + maybeParentHeader + .map( + (parentHeader) -> + protocolSpec + .getFeeMarket() + .dataPricePerGas( + calculateExcessDataGasForParent(protocolSpec, parentHeader))) + .orElse(Wei.ZERO); final TransactionProcessingResult result = transactionProcessor.processTransaction( 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..84841da9bc1 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_DATA_GAS_PER_BLOCK = 786432L; public CancunTargetingGasLimitCalculator( final long londonForkBlock, final BaseFeeMarket feeMarket) { 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 1a1008cea8f..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 @@ -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(", ", "[", "]")); } @@ -110,6 +121,15 @@ public boolean anyMatch(final Predicate predicate) { return this.protocolSpecs.stream().anyMatch(predicate); } + @Override + public Optional hardforkFor( + final Predicate predicate) { + return this.protocolSpecs.stream() + .filter(predicate) + .findFirst() + .map(ScheduledProtocolSpec::fork); + } + @Override public void setPermissionTransactionFilter( final PermissionTransactionFilter permissionTransactionFilter) { 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..3d58cccae22 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 @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.CalculatedDifficultyValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantOmmersHashRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.DataGasValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ExtraDataMaxLengthValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasUsageValidationRule; @@ -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 DataGasValidationRule(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 9a999654cad..bbdfc385664 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 @@ -709,6 +709,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 b57cf266f81..e65b9ce9eb2 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 @@ -340,14 +340,14 @@ 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, + dataGas); final WorldUpdater worldUpdater = worldState.updater(); final Deque messageFrameStack = new ArrayDeque<>(); @@ -380,6 +380,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 = @@ -392,7 +399,6 @@ public TransactionProcessingResult processTransaction( .address(contractAddress) .contract(contractAddress) .inputData(Bytes.EMPTY) - .versionedHashes(transaction.getVersionedHashes()) .code(contractCreationProcessor.getCodeFromEVM(null, initCodeBytes)) .build(); } else { @@ -405,7 +411,6 @@ public TransactionProcessingResult processTransaction( .address(to) .contract(to) .inputData(transaction.getPayload()) - .versionedHashes(transaction.getVersionedHashes()) .code( maybeContract .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode())) @@ -414,7 +419,6 @@ public TransactionProcessingResult processTransaction( } messageFrameStack.addFirst(initialFrame); - if (initialFrame.getCode().isValid()) { while (!messageFrameStack.isEmpty()) { process(messageFrameStack.peekFirst(), operationTracer); @@ -442,8 +446,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 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 777a68ba948..01d35737e41 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,8 +18,13 @@ 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; @@ -29,9 +34,15 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; 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. * @@ -40,6 +51,8 @@ */ public class MainnetTransactionValidator implements TransactionValidator { + private final byte BLOB_COMMITMENT_VERSION_KZG = 0x01; + private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; private final FeeMarket feeMarket; @@ -80,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( @@ -144,6 +165,17 @@ private ValidationResult validateCostAndFee( } } + if (transaction.getType().supportsBlob()) { + final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + if (txTotalDataGas > gasLimitCalculator.currentDataGasLimit()) { + return ValidationResult.invalid( + TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, + String.format( + "total data gas %d exceeds max data gas per block %d", + txTotalDataGas, gasLimitCalculator.currentDataGasLimit())); + } + } + final long intrinsicGasCost = gasCalculator.transactionIntrinsicGasCost( transaction.getPayload(), transaction.isContractCreation()) @@ -249,4 +281,109 @@ private ValidationResult validateTransactionSignature( } return ValidationResult.valid(); } + + 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(); + } + + /* + private VersionedHash hashCommitment(final Bytes32 commitment) { + return new VersionedHash( + VersionedHash.SHA256_VERSION_ID, Sha256Hash.hash(commitment)); + } + + */ + + 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/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/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/feemarket/CancunFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java index 68f0ba26a63..8a570fecd85 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 @@ -26,7 +26,7 @@ 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 DATA_GAS_PRICE_UPDATE_FRACTION = BigInteger.valueOf(3338477); public CancunFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { @@ -39,7 +39,7 @@ public boolean implementsDataFee() { } @Override - public Wei dataPrice(final DataGas excessDataGas) { + public Wei dataPricePerGas(final DataGas excessDataGas) { final var dataGasPrice = Wei.of( fakeExponential( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessDataGasCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessDataGasCalculator.java new file mode 100644 index 00000000000..75e179595a5 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessDataGasCalculator.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.DataGas; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; + +/** Calculates the excess data gas for a parent block header. */ +public class ExcessDataGasCalculator { + /** + * public class ExcessDataGasCalculator { /** Calculates the excess data gas for a parent block + * header. + * + * @param protocolSpec The protocol specification. + * @param parentHeader The parent block header. + * @return The excess data gas. + */ + public static DataGas calculateExcessDataGasForParent( + final ProtocolSpec protocolSpec, final BlockHeader parentHeader) { + // Blob Data Excess + long headerExcess = + protocolSpec + .getGasCalculator() + .computeExcessDataGas( + parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), + parentHeader.getDataGasUsed().orElse(0L)); + return DataGas.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..a44e7f629e4 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 @@ -57,7 +57,7 @@ static FeeMarket legacy() { return new LegacyFeeMarket(); } - default Wei dataPrice(final DataGas excessDataGas) { + default Wei dataPricePerGas(final DataGas excessDataGas) { 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/DataGasValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRule.java new file mode 100644 index 00000000000..2849c7a99e0 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRule.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.DataGas; +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 data gas matches the calculated value. */ +public class DataGasValidationRule implements DetachedBlockHeaderValidationRule { + + private static final Logger LOG = LoggerFactory.getLogger(DataGasValidationRule.class); + + private final GasCalculator gasCalculator; + + public DataGasValidationRule(final GasCalculator gasCalculator) { + this.gasCalculator = gasCalculator; + } + + /** + * Validates the block header by checking if the header's excess data gas matches the calculated + * value based on the parent header. + */ + @Override + public boolean validate(final BlockHeader header, final BlockHeader parent) { + long headerExcessDataGas = header.getExcessDataGas().map(DataGas::toLong).orElse(0L); + long parentExcessDataGas = parent.getExcessDataGas().map(DataGas::toLong).orElse(0L); + long parentDataGasUsed = parent.getDataGasUsed().orElse(0L); + + long calculatedExcessDataGas = + gasCalculator.computeExcessDataGas(parentExcessDataGas, parentDataGasUsed); + + if (headerExcessDataGas != calculatedExcessDataGas) { + LOG.info( + "Invalid block header: header excessDataGas {} and calculated excessDataGas {} do not match", + headerExcessDataGas, + calculatedExcessDataGas); + return false; + } + return true; + } +} 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..e013186e2b5 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 @@ -47,7 +47,7 @@ public enum TransactionInvalidReason { 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..9a76eafee7b 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,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.transaction; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; + import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -230,8 +232,10 @@ public Optional processWithWorldUpdater( final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice( - maybeParentHeader.flatMap(BlockHeader::getExcessDataGas).orElse(DataGas.ZERO)); + .dataPricePerGas( + maybeParentHeader + .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) + .orElse(DataGas.ZERO)); final Transaction transaction = maybeTransaction.get(); final TransactionProcessingResult result = 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 73ecabeee4c..df473612ccc 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 @@ -26,6 +26,7 @@ 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; @@ -442,7 +443,7 @@ private Transaction blobTransaction(final Bytes payload, final Address to) { .payload(payload) .chainId(BigInteger.ONE) .maxFeePerDataGas(Wei.of(1)) - .versionedHashes(List.of(Hash.fromHexStringLenient("0x29"))) + .versionedHashes(List.of(VersionedHash.DEFAULT_VERSIONED_HASH)) .signAndBuild(generateKeyPair()); } 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..9f23a0d044d 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.DataGas; 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 excessDataGas = Optional.empty(); + private Optional dataGasUsed = 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); + excessDataGas.ifPresent(builder::excessDataGas); + dataGasUsed.ifPresent(builder::dataGasUsed); depositsRoot.ifPresent(builder::depositsRoot); builder.blockHeaderFunctions(blockHeaderFunctions); @@ -173,6 +178,16 @@ public BlockHeaderTestFixture depositsRoot(final Hash depositsRoot) { return this; } + public BlockHeaderTestFixture excessDataGas(final DataGas excessDataGas) { + this.excessDataGas = Optional.ofNullable(excessDataGas); + return this; + } + + public BlockHeaderTestFixture dataGasUsed(final Long dataGasUsed) { + this.dataGasUsed = Optional.ofNullable(dataGasUsed); + 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/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..9838ca29204 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 @@ -127,4 +127,9 @@ public Hash getBlockHash() { public Optional getExcessDataGas() { return Optional.empty(); } + + @Override + public Optional getDataGasUsed() { + return Optional.empty(); + } } 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 60e80112895..1ba60c3cb55 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,8 +16,9 @@ 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; @@ -26,14 +27,8 @@ 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.fromHexString("2a".repeat(31))))); private TransactionType transactionType = TransactionType.FRONTIER; @@ -57,8 +52,9 @@ public class TransactionTestFixture { private Optional maxFeePerDataGas = 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) { @@ -89,7 +85,12 @@ public Transaction createTransaction(final KeyPair keys) { 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.versionedHashes( + versionedHashes.orElse(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))); + blobs.ifPresent( + bwc -> { + builder.kzgBlobs(bwc.getKzgCommitments(), bwc.getBlobs(), bwc.getKzgProofs()); + }); break; } @@ -165,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; } @@ -174,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/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java index b2cad642fc2..71479416740 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 @@ -96,6 +96,7 @@ public class LogRollingTests { Hash.ZERO, 0, null, + null, // dataGasUSed null, null, new MainnetBlockHeaderFunctions()); @@ -118,6 +119,7 @@ public class LogRollingTests { Hash.ZERO, 0, null, + null, // dataGasUsed null, null, new MainnetBlockHeaderFunctions()); 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 0adcaa5b8c4..dd81068878b 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 @@ -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))) + .maxFeePerDataGas(Optional.of(Wei.of(5))) .createTransaction(senderKeys); fail(); } catch (IllegalArgumentException iea) { 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/mainnet/BodyValidationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/BodyValidationTest.java index 508af1f5a45..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,6 +23,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** Tests for {@link BodyValidation}. */ @@ -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/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index dd4d19115da..e7a9028a497 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 @@ -23,6 +23,7 @@ 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.when; @@ -31,10 +32,16 @@ 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.TransactionTestFixture; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; @@ -43,6 +50,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; import java.math.BigInteger; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; @@ -466,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))) + .maxFeePerDataGas(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() { + when(gasCalculator.dataGasCost(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))) + .maxFeePerDataGas(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(); } 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..9c3636c30e4 --- /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.DataGas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class CancunFeeMarketTest { + + private static final int DATA_GAS_PER_BLOB = 131072; + + @Test + void dataPricePerGas() { + CancunFeeMarket cancunFeeMarket = new CancunFeeMarket(0, Optional.empty()); + // when no excess data gas, data price per gas is 1 + assertEquals(1, cancunFeeMarket.dataPricePerGas(DataGas.ZERO).getAsBigInteger().intValue()); + + record DataGasPricing(long excess, long price) {} + List testVector = new ArrayList<>(); + + int numBlobs = 1; + long price = 1; + while (price <= 1000) { + price = dataGasPrice(DataGas.of(numBlobs * DATA_GAS_PER_BLOB)); + var testCase = new DataGasPricing(numBlobs * DATA_GAS_PER_BLOB, price); + testVector.add(testCase); + numBlobs++; + } + + testVector.stream() + .forEach( + dataGasPricing -> { + assertEquals( + dataGasPricing.price, + cancunFeeMarket + .dataPricePerGas(DataGas.of(dataGasPricing.excess)) + .getAsBigInteger() + .intValue()); + }); + } + + private long dataGasPrice(final DataGas 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/ZeroBaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java index 3c77f9d2b5d..44839c437f7 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 @@ -147,6 +147,6 @@ public void implementsDataFeedShouldReturnFalse() { @Test public void dataPriceShouldReturnsZero() { - assertThat(zeroBaseFeeMarket.dataPrice(DataGas.ONE)).isEqualTo(Wei.ZERO); + assertThat(zeroBaseFeeMarket.dataPricePerGas(DataGas.ONE)).isEqualTo(Wei.ZERO); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRuleTest.java new file mode 100644 index 00000000000..d5831766298 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRuleTest.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.DataGas; +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 DataGasValidationRule} class. */ +public class DataGasValidationRuleTest { + + private CancunGasCalculator gasCalculator; + private DataGasValidationRule dataGasValidationRule; + + @BeforeEach + public void setUp() { + gasCalculator = new CancunGasCalculator(); + dataGasValidationRule = new DataGasValidationRule(gasCalculator); + } + + /** Tests that the header data gas matches the calculated data gas and passes validation. */ + @Test + public void validateHeader_DataGasMatchesCalculated_SuccessValidation() { + long target = gasCalculator.getTargetDataGasPerBlock(); + + // Create parent header + final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); + parentBuilder.excessDataGas(DataGas.of(1L)); + parentBuilder.dataGasUsed(target); + final BlockHeader parentHeader = parentBuilder.buildHeader(); + + // Create block header with matching excessDataGas + final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); + headerBuilder.excessDataGas(DataGas.of(1L)); + final BlockHeader header = headerBuilder.buildHeader(); + + assertThat(dataGasValidationRule.validate(header, parentHeader)).isTrue(); + } + + /** + * Tests that the header data gas is different from the calculated data gas and fails validation. + */ + @Test + public void validateHeader_DataGasDifferentFromCalculated_FailsValidation() { + long target = gasCalculator.getTargetDataGasPerBlock(); + + // Create parent header + final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); + parentBuilder.excessDataGas(DataGas.of(1L)); + parentBuilder.dataGasUsed(target); + final BlockHeader parentHeader = parentBuilder.buildHeader(); + + // Create block header with different excessDataGas + final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); + final BlockHeader header = headerBuilder.buildHeader(); + + assertThat(dataGasValidationRule.validate(header, parentHeader)).isFalse(); + } +} 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..f642ed46d6a --- /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", + "MaxFeePerDataGas": "100", + "Data": "0x77918d0c4153776b" + }, + "RawEncodedTransaction": "0x033c00000076010000a6010000b0b4fa487696b3e1ab9de18f8e1d295e46b1048a68e18787145f5bc1e34faa6178b4018747674c3849fa7c1d38f2f07b4500000000935bdf0c90c47aaaf38ae7eed1380cfecea8c0a2cc5c93a4cbbba10976e306256a2f48215abc90b8edf7cdcfe226eb5841d86fa19cd4b5446dc075376fd59b0c330500000000000000000000000000000000000000000000000000000000000001000000000000003200000000000000000000000000000000000000000000000000000000000000e803000000000000000000000000000000000000000000000000000000000000a086010000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000006400000000000000000000000000000000000000000000000000000000000000d50000000145ae5777c9b35eb16280e423b0d7c91c06c66b5801f4af1847885b145b1a91f61c6c4dc13be1239debecf751101ee69c16f58904b8f1de4f6734fbcb617df946d87d8dd210440bb33ff8d84e86aa08660ee7beec27127438f5882f5f9b74fecef38c437c77918d0c4153776b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Input": { + "PrivateKey": "67f45650acc5dc426fc424348f8d9f07032c439f03797c4beba096a6e23e666b", + "To": "0x549A51956bd364D8bB2Efb1F1eA4436e8D7764Ff", + "Nonce": 2, + "Value": "1", + "GasLimit": 50000, + "GasPrice": "1234", + "PriorityGasPrice": "100", + "MaxFeePerDataGas": "200", + "Data": "0x61f1628061be533586f64f50678a793e64a207a5df408217ed91c94f3c6f61bf6e2f6ff982b7ac3f300face1b52ae3fc68ee030fdc3150d73a056bd4df661059c6d1cb08ea2b39d0d49b0efaa75b8b61fb7f2b9caca6896aea156ed0304701796c517e2b010e387fefc702dabc6b4d2c732a173d33e0c272701e4f8668bad602" + }, + "RawEncodedTransaction": "0x033c00000076010000a6010000b6fabe6947368cfe7c5ac38eab67c0a3d5013848cb3b6600e0a0e205c1719577f5cd89b9e6c256ef9bc131d7550b9a2945000000002548c5fb3971907ef5a3ec7e092ff4abc602dfa5859805cba9ec3a725784f864954c50ef43cc745af6631688c6b819881eb3dab130cef3aee2bcb529f07de919330500000000000000000000000000000000000000000000000000000000000002000000000000006400000000000000000000000000000000000000000000000000000000000000d20400000000000000000000000000000000000000000000000000000000000050c3000000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d5000000c800000000000000000000000000000000000000000000000000000000000000d500000001549a51956bd364d8bb2efb1f1ea4436e8d7764ff015a6aa788d53d27bf35bafc1c45ff8734767eeeea3c334eacd3b759090f7937813e3a0cbc3a233eee92ccba94c8d76aa68c8a23257a81fa9aac7d0eabf89bb6ea484955196fc9a0ab07522ca3d50ab361f1628061be533586f64f50678a793e64a207a5df408217ed91c94f3c6f6100bf6e2f6ff982b7ac3f300face1b52ae3fc68ee030fdc3150d73a056bd4df66001059c6d1cb08ea2b39d0d49b0efaa75b8b61fb7f2b9caca6896aea156ed030004701796c517e2b010e387fefc702dabc6b4d2c732a173d33e0c272701e4f860068bad6020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Input": { + "PrivateKey": "2e2b5c749eab38b8eca6b788c70429580ffa8eb79ab9635b95af00c6f6cba661", + "To": "0xa39c4e1B259473fbcC5213a0613eB53a8C50bf76", + "Nonce": 3, + "Value": "1", + "GasLimit": 70000, + "GasPrice": "999", + "PriorityGasPrice": "10", + "MaxFeePerDataGas": "20", + "Data": "0xa9fc4e91a83d0307d0aa69047208b24e15bd81098f9f580176ddf17604604b9259ddb3477cd87b6fd26d00615d65bb7e09597c1ea058e700a3da71696887edc6c0383f63e6a51b313afcf46f7159649cd4da51903c820aa577e93adc54cb62bd05a5d1bc8f9b4bcbf8de9670040106859f3c78b5f4d0e69804e743b905506f23503f720744f6a7e5ade176064fdc43803dcd6a12eda8d523fea35c4fe7e9537fa48f87c7b23f9f01e7ba0aa4f6688dbdb2646ec62d0156a1529121c702d00c73f27add8d238d04248a2c5b76e4b108116b2f9699523521586464b86dd4d6048c35719131dc4828ab8c95cb2aeb29fde8163f10994bfcffaf041250da0f2525a8" + }, + "RawEncodedTransaction": "0x033c00000076010000a6010000b9f0f8d300dd1026eaae3514ec7c5256da8d5cab3c2dad5de17b1d313d090d4a8e3c16a5a18958689c5bfc8d796469b2450000000022914d549bf0a6e1768dd8bd194398b90d3ff9e106e2eaf49ea4b6c3393bdc4e3095de1696ff03c6411f4253caaf8a67ddc6960621c62427c5175cbc4b54ba62330500000000000000000000000000000000000000000000000000000000000003000000000000000a00000000000000000000000000000000000000000000000000000000000000e7030000000000000000000000000000000000000000000000000000000000007011010000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000001400000000000000000000000000000000000000000000000000000000000000d500000001a39c4e1b259473fbcc5213a0613eb53a8c50bf7601993d186e446474c02a7128f7664b21f84cf71bf23c094891c7a0eb50d60aac82fe74ca635e5232c171eb8389f4b572b5da6e6b0f1f352a6e3baa9730f255991994a6df1604fcb4a6b08b125e6de7c4a9fc4e91a83d0307d0aa69047208b24e15bd81098f9f580176ddf17604604b009259ddb3477cd87b6fd26d00615d65bb7e09597c1ea058e700a3da7169688700edc6c0383f63e6a51b313afcf46f7159649cd4da51903c820aa577e93adc5400cb62bd05a5d1bc8f9b4bcbf8de9670040106859f3c78b5f4d0e69804e743b90005506f23503f720744f6a7e5ade176064fdc43803dcd6a12eda8d523fea35c004fe7e9537fa48f87c7b23f9f01e7ba0aa4f6688dbdb2646ec62d0156a152910021c702d00c73f27add8d238d04248a2c5b76e4b108116b2f969952352158640064b86dd4d6048c35719131dc4828ab8c95cb2aeb29fde8163f10994bfcffaf00041250da0f2525a80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Input": { + "PrivateKey": "ee15ba623c2a495eefc9b8dc7447ff70bee325cc1f75f5170a71dc4dd3227f13", + "To": "0xd59399657A78bb69dEE83C416C13Be711e02fA23", + "Nonce": 4, + "Value": "1", + "GasLimit": 21000, + "GasPrice": "1001", + "PriorityGasPrice": "35", + "MaxFeePerDataGas": "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 0000000000000000000000000000000000000000..908adb571ca8cec859dbd68f5fb5b3f582f08add GIT binary patch literal 1807 zcmey#&hwK=Yr%_zd473|j)rPFu!Z|}9C8#mR&t0{NjFLCRK?mQD^?s|AbZC5#l7RP zRjXUKrf)lQMe4GUtMrtv65$UEo&Gvpne0C0XPpEOD__)xB1Nf7hlF28z4QHOvY=?w zv0|_GTfKpw!@{C`zx(T|Pcqr?Q!n=a?)g$dMxSpkNLeJ9=yh)0k>jR2qR$j4PGDT% zwq4WqeC)p0lRU#_)#)yHaBH_`#OAKYam!ZZ{#MLB@?mS$U4iuYfGaku_eysfrS4>8 z80ny)>C4|1#*>E|nwj1=w4_9Q{?g@_T9T1kl$)8CvY?$qnDM8)#;+#jAZ{i5SMe%o z4m+|17O@5&JoAe8-QMNQrq+~)q6s&qZF<=8vrpbGZ3 zbDhBxG((bGj&Ixbo9~D4(+3ac`RXY!&Z_>^_~7U6+PBkoD&UJgGpN%NQlzx-sUsvG zV8RSG=>U*qTEPJ|6+3kmC=9}c%mk@n{J*)YYUbld#?deAk9*gzlDrx$#M_%|IIsSnW}_n#+B&a` zZ`+;p`<4Hmwy|e!n{kn~%~#5O@&~n5%0Xd;_Lb6mew&GZn3}TVGS6E^eL+IO^%3MG z5I8l<8p6O%@(~D5a)OJHnMlEPHRzFR!W(_D?uS>FS;T&mDOmqRqn}~%T5;Wl%RX)S z1k0NYnv73&x*QbzVK(zevVEbIc&W~%{-r0j_$o0)3Xk>Kjjr;#?_DxEOZ?F33 z@k++;`{$8$zluRU{MYHC6^on+1s6PU4!!1vv#~JP2?Qr{-o&CEMF^HR85TbjM3F$_ zfb-^w%b6Qf%%nOKHFAEhwm!%|O|f+aqwJ3^&B7DQ*LZqWFRnYdW|jQGx9>LhG|!F| Mn|!4@bHjlH04i9Uwg3PC literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..908adb571ca8cec859dbd68f5fb5b3f582f08add GIT binary patch literal 1807 zcmey#&hwK=Yr%_zd473|j)rPFu!Z|}9C8#mR&t0{NjFLCRK?mQD^?s|AbZC5#l7RP zRjXUKrf)lQMe4GUtMrtv65$UEo&Gvpne0C0XPpEOD__)xB1Nf7hlF28z4QHOvY=?w zv0|_GTfKpw!@{C`zx(T|Pcqr?Q!n=a?)g$dMxSpkNLeJ9=yh)0k>jR2qR$j4PGDT% zwq4WqeC)p0lRU#_)#)yHaBH_`#OAKYam!ZZ{#MLB@?mS$U4iuYfGaku_eysfrS4>8 z80ny)>C4|1#*>E|nwj1=w4_9Q{?g@_T9T1kl$)8CvY?$qnDM8)#;+#jAZ{i5SMe%o z4m+|17O@5&JoAe8-QMNQrq+~)q6s&qZF<=8vrpbGZ3 zbDhBxG((bGj&Ixbo9~D4(+3ac`RXY!&Z_>^_~7U6+PBkoD&UJgGpN%NQlzx-sUsvG zV8RSG=>U*qTEPJ|6+3kmC=9}c%mk@n{J*)YYUbld#?deAk9*gzlDrx$#M_%|IIsSnW}_n#+B&a` zZ`+;p`<4Hmwy|e!n{kn~%~#5O@&~n5%0Xd;_Lb6mew&GZn3}TVGS6E^eL+IO^%3MG z5I8l<8p6O%@(~D5a)OJHnMlEPHRzFR!W(_D?uS>FS;T&mDOmqRqn}~%T5;Wl%RX)S z1k0NYnv73&x*QbzVK(zevVEbIc&W~%{-r0j_$o0)3Xk>Kjjr;#?_DxEOZ?F33 z@k++;`{$8$zluRU{MYHC6^on+1s6PU4!!1vv#~JP2?Qr{-o&CEMF^HR85TbjM3F$_ zfb-^w%b6Qf%%nOKHFAEhwm!%|O|f+aqwJ3^&B7DQ*LZqWFRnYdW|jQGx9>LhG|!F| Mn|!4@bHjlH04i9Uwg3PC literal 0 HcmV?d00001 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/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 fccdae23f8e..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 @@ -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/sync/backwardsync/ChainForTestCreator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java index 0d0b50858be..406e5950401 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 extractTransactions( txNode); continue; } - // FUTURE: placeholder code until 4844 PR merges - // List entries = new ArrayList<>(blobVersionedHashes.size()); - // for (JsonNode versionedHashNode : blobVersionedHashes) { - // entries.add( - // new VersionedHash(Bytes32.fromHexString(versionedHashNode.textValue()))); - // } - // builder.versionedHashes(entries); + + 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")) { @@ -251,7 +252,7 @@ static T8nResult runTest( 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 dataGasPrice = protocolSpec.getFeeMarket().dataPricePerGas(DataGas.ZERO); List receipts = new ArrayList<>(); List invalidTransactions = new ArrayList<>(rejections); 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 index 5e3c6ea4754..952ca1d0b65 100644 --- 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 @@ -61,36 +61,36 @@ "stdout": { "alloc": { "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { - "balance": "0x48540" + "balance": "0x48552" }, "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x3635c9adc5de90ee80", + "balance": "0x3635c9adc5de90ee44", "nonce": "0x1" } }, "body": "0xf873f871800a8405f5e1008080a4600d8060175f39805f80f05f805f805f855af1505ffffe600280600b5f39805ff3fe5fff1ba0f2bb558b73cfb96466c41785fdd0f1e367b4703d49653e617cffdb7316a01e87a011e0423aeea027a1e48dc3adffe2b27652d8154599f10b6f552d51b1fcb632ae", "result": { - "stateRoot": "0x8d6ff9ecb860b2ca140a73ae8591615e384a4e397d859af831b4a475e47ff7b0", + "stateRoot": "0xe8a9461dcfdbaa48bbddca4f4baa439e45f1489827e5deeb2797363323e34769", "txRoot": "0x35ab0ce85af281d6e600d467fb3ed12063994cc9e105cbdb4eb1ba65ed9edddf", - "receiptsRoot": "0x2f9ef11d9889ea86d77151c8a6cf578fed535563e1a016e67997d22984ca1bef", + "receiptsRoot": "0xdf87447856d3a36db48c7ec997ff29845eeb513cb49aaa20547290f64f3710d1", "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [ { "root": "0x", "status": "0x1", - "cumulativeGasUsed": "0x181c0", + "cumulativeGasUsed": "0x181c6", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logs": null, "transactionHash": "0xd954e10ebf0b55b71512b53a6ebae09372ccc6b2bf87b199e8aa8a5c4f757430", "contractAddress": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", - "gasUsed": "0x181c0", + "gasUsed": "0x181c6", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } ], "currentDifficulty": null, - "gasUsed": "0x181c0", + "gasUsed": "0x181c6", "currentBaseFee": "0x7", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } 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 index 99acfb9e058..ac323e74a01 100644 --- 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 @@ -71,6 +71,9 @@ }, "stdout": { "alloc": { + "0x0000000000000000000000000000000000000100": { + "balance": "0x1" + }, "0x0000000000000000000000000000000000000200": { "balance": "0x1" }, @@ -79,24 +82,32 @@ "nonce": "0x1" }, "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x43e39" + "balance": "0x0", + "nonce": "0x1" } }, "result": { - "stateRoot": "0xa6c91f68d20d3b6137ca1184a3995344256f0b53410b3577c9ab0a764a782cfb", - "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot": "0xd29f5a8dd1a63e0a299009f546bdf447fb61f1604d95e737bd8eb3c089d78060", + "txRoot": "0xda80a6acad2089c995d9df6604f54f2102eb7a3bc73b001957ef851ee3606902", + "receiptsRoot": "0xeaa8c40899a61ae59615cf9985f5e2194f8fd2b57d273be63bde6733e89b12ab", "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "receipts": [], - "rejected": [ + "receipts": [ { - "index": 0, - "error": "Unsupported transaction type 3" + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x5208", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x2f68a5bb6b843147e9ef8628047b6c5d5a0df834dc572007af7d4fce8e644c20", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" } ], "currentDifficulty": null, - "gasUsed": "0x0", + "gasUsed": "0x5208", "currentBaseFee": "0x7", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" } 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/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..3171a7eee14 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 @@ -164,6 +164,7 @@ 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("hash") final String hash) { super( @@ -188,6 +189,7 @@ public ReferenceTestBlockHeader( Hash.fromHexString(mixHash), // mixHash Bytes.fromHexStringLenient(nonce).toLong(), withdrawalsRoot != null ? Hash.fromHexString(withdrawalsRoot) : null, + dataGasUsed != null ? Long.parseLong(dataGasUsed) : 0, excessDataGas != null ? DataGas.fromHexString(excessDataGas) : null, depositsRoot != null ? Hash.fromHexString(depositsRoot) : null, new BlockHeaderFunctions() { 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 cc0d6d7d5c3..14d9b13348b 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,7 +19,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -134,7 +133,8 @@ public ReferenceTestEnv( Optional.ofNullable(random).map(Difficulty::fromHexString).orElse(Difficulty.ZERO), 0L, null, // withdrawalsRoot - currentExcessDataGas == null ? null : DataGas.fromHexString(currentExcessDataGas), + null, // dataGasUsed + null, // excessDataGas null, // depositsRoot new MainnetBlockHeaderFunctions()); this.parentDifficulty = parentDifficulty; 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..0a975bc941e 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 @@ -147,7 +147,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { 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 dataGasPrice = protocolSpec(spec.getFork()).getFeeMarket().dataPricePerGas(DataGas.ZERO); final TransactionProcessingResult result = processor.processTransaction( blockchain, 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 ce6ee0391d6..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 @@ -115,6 +115,12 @@ 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(); 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/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java index 1dd7801ce15..1c7adf20850 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 @@ -19,6 +19,7 @@ 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; @@ -241,7 +242,7 @@ public enum Type { private Optional revertReason; private final Map contextVariables; - private final Optional> versionedHashes; + private final Optional> versionedHashes; private final Table transientStorage = HashBasedTable.create(); @@ -286,7 +287,7 @@ private MessageFrame( final int maxStackSize, final Set
    accessListWarmAddresses, final Multimap accessListWarmStorage, - final Optional> versionedHashes) { + final Optional> versionedHashes) { this.type = type; this.messageFrameStack = messageFrameStack; this.parentMessageFrame = messageFrameStack.peek(); @@ -1426,7 +1427,7 @@ public void commitTransientStorage() { * * @return optional list of hashes */ - public Optional> getVersionedHashes() { + public Optional> getVersionedHashes() { return versionedHashes; } @@ -1464,7 +1465,7 @@ public static class Builder { private Set
    accessListWarmAddresses = emptySet(); private Multimap accessListWarmStorage = HashMultimap.create(); - private Optional> versionedHashes; + private Optional> versionedHashes = Optional.empty(); /** * Sets Type. @@ -1736,7 +1737,7 @@ 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; } @@ -1760,6 +1761,7 @@ private void validate() { checkState(completer != null, "Missing message frame completer"); checkState(miningBeneficiary != null, "Missing mining beneficiary"); checkState(blockHashLookup != null, "Missing block hash lookup"); + checkState(versionedHashes != null, "Missing optional versioned hashes"); } /** 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..1939f107002 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,6 +14,8 @@ */ package org.hyperledger.besu.evm.gascalculator; +import static org.hyperledger.besu.datatypes.Address.KZG_POINT_EVAL; + /** * Gas Calculator for Cancun * @@ -22,13 +24,33 @@ *
  • Data 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 data gas cost per blob. This is the gas cost for each blob of data that is added to the + * block. + */ + public static final long DATA_GAS_PER_BLOB = 1 << 17; + + /** The target data gas per block. */ + public static final long TARGET_DATA_GAS_PER_BLOCK = 0x60000; // EIP-1153 @Override @@ -46,6 +68,25 @@ public long dataGasCost(final int blobCount) { return DATA_GAS_PER_BLOB * blobCount; } + /** + * Retrieves the target data gas per block. + * + * @return The target data gas per block. + */ + public long getTargetDataGasPerBlock() { + return TARGET_DATA_GAS_PER_BLOCK; + } + + /** + * Computes the excess data gas for a given block based on the parent's excess data gas and data + * gas used. If the sum of parent's excess data gas and parent's data gas used is less than the + * target data gas per block, the excess data gas is calculated as 0. Otherwise, it is computed as + * the difference between the sum and the target data gas per block. + * + * @param parentExcessDataGas The excess data gas of the parent block. + * @param newBlobs data gas incurred by current block + * @return The excess data gas for the current block. + */ @Override public long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { final long consumedDataGas = dataGasCost(newBlobs); @@ -56,4 +97,14 @@ public long computeExcessDataGas(final long parentExcessDataGas, final int newBl } return currentExcessDataGas - TARGET_DATA_GAS_PER_BLOCK; } + + @Override + public long computeExcessDataGas(final long parentExcessDataGas, final long dataGasUsed) { + final long currentExcessDataGas = parentExcessDataGas + dataGasUsed; + + if (currentExcessDataGas < TARGET_DATA_GAS_PER_BLOCK) { + return 0L; + } + return currentExcessDataGas - TARGET_DATA_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 cd8b659051d..8f523fb4689 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 @@ -534,4 +534,15 @@ default long dataGasCost(final int blobCount) { default long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { return 0L; } + + /** + * Compute the new value for the excess data gas, given the parent value and the data gas used + * + * @param parentExcessDataGas excess data gas from the parent + * @param dataGasUsed data gas used + * @return the new excess data gas value + */ + default long computeExcessDataGas(final long parentExcessDataGas, final long dataGasUsed) { + 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 5cd11e55a3a..12618e7ee41 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 @@ -217,6 +217,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { .miningBeneficiary(frame.getMiningBeneficiary()) .blockHashLookup(frame.getBlockHashLookup()) .maxStackSize(frame.getMaxStackSize()) + .versionedHashes(frame.getVersionedHashes()) .build(); frame.incrementRemainingGas(cost); 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 9496624334a..9b364347100 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 @@ -137,41 +137,42 @@ 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); - frame.addCreate(contractAddress); + final Address contractAddress = targetContractAddress(parent); + parent.addCreate(contractAddress); final long childGasStipend = - gasCalculator().gasAvailableForChildCreate(frame.getRemainingGas()); - frame.decrementRemainingGas(childGasStipend); + gasCalculator().gasAvailableForChildCreate(parent.getRemainingGas()); + parent.decrementRemainingGas(childGasStipend); final MessageFrame childFrame = MessageFrame.builder() .type(MessageFrame.Type.CONTRACT_CREATION) - .messageFrameStack(frame.getMessageFrameStack()) - .worldUpdater(frame.getWorldUpdater().updater()) + .messageFrameStack(parent.getMessageFrameStack()) + .worldUpdater(parent.getWorldUpdater().updater()) .initialGas(childGasStipend) .address(contractAddress) - .originator(frame.getOriginatorAddress()) + .originator(parent.getOriginatorAddress()) .contract(contractAddress) - .gasPrice(frame.getGasPrice()) + .gasPrice(parent.getGasPrice()) .inputData(Bytes.EMPTY) - .sender(frame.getRecipientAddress()) + .sender(parent.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()) + .blockValues(parent.getBlockValues()) + .depth(parent.getMessageStackDepth() + 1) + .completer(child -> complete(parent, child, evm)) + .miningBeneficiary(parent.getMiningBeneficiary()) + .blockHashLookup(parent.getBlockHashLookup()) + .maxStackSize(parent.getMaxStackSize()) + .versionedHashes(parent.getVersionedHashes()) .build(); - frame.getMessageFrameStack().addFirst(childFrame); - frame.setState(MessageFrame.State.CODE_SUSPENDED); + parent.getMessageFrameStack().addFirst(childFrame); + parent.setState(MessageFrame.State.CODE_SUSPENDED); } private void complete(final MessageFrame frame, final MessageFrame childFrame, final EVM evm) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java index eda3f5dfd4e..9439709ca3e 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java @@ -14,13 +14,12 @@ */ 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; @@ -47,13 +46,19 @@ public DataHashOperation(final GasCalculator 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); } 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/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..e0a7edc2a43 --- /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("dataGasses") + public void shouldCalculateExcessDataGasCorrectly( + final long parentExcess, final long used, final long expected) { + assertThat(gasCalculator.computeExcessDataGas(parentExcess, (int) used)).isEqualTo(expected); + } + + static Iterable dataGasses() { + long targetGasPerBlock = CancunGasCalculator.TARGET_DATA_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.DATA_GAS_PER_BLOB), + Arguments.of(targetGasPerBlock, 3, targetGasPerBlock)); + } +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java index 6e334fea67c..02f4964e859 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java @@ -21,26 +21,32 @@ 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.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 { + private static final String testVersionedHash = + "0x01cafebabeb0b0facedeadbeefbeef0001cafebabeb0b0facedeadbeefbeef00"; + @Test void putsHashOnStack() { - Hash version0Hash = Hash.fromHexStringLenient("0xcafebabeb0b0facedeadbeef"); - List versionedHashes = List.of(version0Hash); + VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); + List versionedHashes = Arrays.asList(version0Hash); DataHashOperation getHash = new DataHashOperation(new LondonGasCalculator()); MessageFrame frame = mock(MessageFrame.class); when(frame.popStackItem()).thenReturn(Bytes.of(0)); @@ -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()); + DataHashOperation getHash = new DataHashOperation(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); + DataHashOperation getHash = new DataHashOperation(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); + DataHashOperation getHash = new DataHashOperation(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/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/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/verification-metadata.xml b/gradle/verification-metadata.xml index c9a2105d52d..5150a2d83c1 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6039,15 +6039,15 @@ - - - + + + - - + + - - + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 4089bbb3014..c69910057c2 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -158,7 +158,7 @@ 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') { entry 'arithmetic' diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 58995ab2a51..5fa8a997c10 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 @@ -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 = 'd2bQ74zD+rKQgzZO97OO2976iJ3ho5dF2ZX4NM+Zt38=' + knownHash = 'DyHMAiRn7aROnI2DCHrrkhU9szOs+NbI6FAxELrwEGQ=' } check.dependsOn('checkAPIChanges') 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..b06f020ad8b 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 @@ -208,4 +208,12 @@ default Optional getPrevRandao() { */ @Unstable Optional getExcessDataGas(); + + /** + * The data_gas_used of this header. + * + * @return The data_gas_used of this header. + */ + @Unstable + Optional getDataGasUsed(); } From ba2fc3d667a459d120bef973c7fe02262d33dbb8 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Thu, 27 Jul 2023 01:30:49 +0800 Subject: [PATCH 28/51] replace ArrayList with HashSet for rpcMethodExists check (#5708) Signed-off-by: thinkAfCod Co-authored-by: Sally MacFarlane --- .../org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 18fe0d87ac5..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"), @@ -192,7 +192,7 @@ public String getMethodName() { } static { - allMethodNames = new ArrayList<>(); + allMethodNames = new HashSet<>(); for (RpcMethod m : RpcMethod.values()) { allMethodNames.add(m.getMethodName()); } From 403297b874b68cb414c4bf13e98549b3597c61ca Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 26 Jul 2023 12:27:17 -0600 Subject: [PATCH 29/51] EIP-4844 testing support (#5702) Add two new fields to reference tests (versionedHashes, maxFeePerDataGas) Rename DataHash to BlobHash (to align with EIP4844 text) Signed-off-by: Danno Ferrin --- .../besu/datatypes/VersionedHash.java | 18 +++++++++++++++++- .../StateTestVersionedTransaction.java | 16 +++++++++++++++- .../org/hyperledger/besu/evm/MainnetEVMs.java | 6 +++--- ...shOperation.java => BlobHashOperation.java} | 18 +++++++----------- ...ionTest.java => BlobHashOperationTest.java} | 12 ++++++------ 5 files changed, 48 insertions(+), 22 deletions(-) rename evm/src/main/java/org/hyperledger/besu/evm/operation/{DataHashOperation.java => BlobHashOperation.java} (84%) rename evm/src/test/java/org/hyperledger/besu/evm/operations/{DataHashOperationTest.java => BlobHashOperationTest.java} (92%) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java index 97cb093f4d8..21f296e0ae1 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java @@ -17,6 +17,7 @@ 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; @@ -37,7 +38,7 @@ public class VersionedHash { public static final byte SHA256_VERSION_ID = 1; /** A default versioned hash, nonsensical but valid. */ - public static VersionedHash DEFAULT_VERSIONED_HASH = + public static final VersionedHash DEFAULT_VERSIONED_HASH = new VersionedHash(SHA256_VERSION_ID, Hash.ZERO); /** @@ -68,6 +69,21 @@ public VersionedHash(final Bytes32 typedHash) { 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. * 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..e8f171fafe0 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 maxFeePerDataGas; + 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("maxFeePerDataGas") final String maxFeePerDataGas, + @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.maxFeePerDataGas = + Optional.ofNullable(maxFeePerDataGas).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(maxFeePerDataGas).ifPresent(transactionBuilder::maxFeePerDataGas); + transactionBuilder.versionedHashes(blobVersionedHashes); transactionBuilder.guessType(); if (transactionBuilder.getTransactionType().requiresChainId()) { 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 4df9415a108..6398f23a507 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -32,6 +32,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 +49,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; @@ -847,8 +847,8 @@ public static void registerCancunOperations( registry.put(new TStoreOperation(gasCalculator)); registry.put(new TLoadOperation(gasCalculator)); - // EIP-4844 DATAHASH - registry.put(new DataHashOperation(gasCalculator)); + // EIP-4844 BLOBHASH + registry.put(new BlobHashOperation(gasCalculator)); // EIP-5656 MCOPY registry.put(new MCopyOperation(gasCalculator)); 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 84% 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 9439709ca3e..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 @@ -24,24 +24,25 @@ 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 @@ -67,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/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java similarity index 92% 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 02f4964e859..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 @@ -26,7 +26,7 @@ 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; @@ -38,7 +38,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.Test; -class DataHashOperationTest { +class BlobHashOperationTest { private static final String testVersionedHash = "0x01cafebabeb0b0facedeadbeefbeef0001cafebabeb0b0facedeadbeefbeef00"; @@ -47,7 +47,7 @@ class DataHashOperationTest { void putsHashOnStack() { VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); List versionedHashes = Arrays.asList(version0Hash); - DataHashOperation getHash = new DataHashOperation(new LondonGasCalculator()); + 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)); @@ -63,7 +63,7 @@ void pushesZeroOnBloblessTx() { EVM fakeEVM = mock(EVM.class); - DataHashOperation getHash = new DataHashOperation(new CancunGasCalculator()); + BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator()); MessageFrame frame = mock(MessageFrame.class); when(frame.popStackItem()).thenReturn(Bytes.of(0)); when(frame.getVersionedHashes()).thenReturn(Optional.empty()); @@ -84,7 +84,7 @@ void pushesZeroOnBloblessTx() { void pushZeroOnVersionIndexOutOFBounds() { VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); List versionedHashes = Arrays.asList(version0Hash); - DataHashOperation getHash = new DataHashOperation(new CancunGasCalculator()); + 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)); @@ -99,7 +99,7 @@ void pushZeroOnVersionIndexOutOFBounds() { public void pushZeroWhenPopsMissingUint256SizedIndex() { VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); List versionedHashes = Arrays.asList(version0Hash); - DataHashOperation getHash = new DataHashOperation(new CancunGasCalculator()); + 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)); From 56768060def1995fba93305eadd2d406e8e0fa54 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 27 Jul 2023 12:51:37 -0700 Subject: [PATCH 30/51] Promote segmented storage (#5700) promote segmented storage to plugin-api, implement SegmentedInMemoryKeyValueStorage Signed-off-by: garyschulte --- .../controller/BesuControllerBuilder.java | 5 +- .../besu/cli/CommandTestAbstract.java | 3 +- .../storage/StorageSubCommandTest.java | 42 +-- .../controller/BesuControllerBuilderTest.java | 1 - .../common/bft/BftContextBuilder.java | 19 +- .../operations/OperationBenchmarkHelper.java | 4 +- ...nsaiSnapshotWorldStateKeyValueStorage.java | 25 +- .../BonsaiWorldStateKeyValueStorage.java | 173 +++++----- .../storage/BonsaiWorldStateLayerStorage.java | 24 +- .../storage/flat/FlatDbReaderStrategy.java | 48 +-- .../flat/FullFlatDbReaderStrategy.java | 20 +- .../flat/PartialFlatDbReaderStrategy.java | 18 +- .../bonsai/worldview/BonsaiWorldState.java | 54 +++- .../ethereum/storage/StorageProvider.java | 9 +- .../keyvalue/KeyValueStorageProvider.java | 67 ++-- .../KeyValueStorageProviderBuilder.java | 6 +- .../core/InMemoryKeyValueStorageProvider.java | 5 +- .../bonsai/BonsaiWorldStateArchiveTest.java | 51 +-- .../BonsaiWorldStateKeyValueStorageTest.java | 25 +- .../besu/ethereum/bonsai/LogRollingTests.java | 60 ++-- .../besu/ethereum/bonsai/RollingImport.java | 33 +- .../worldstate/MarkSweepPrunerTest.java | 12 +- .../ethereum/eth/transactions/TestNode.java | 6 +- ethereum/evmtool/txs.rlp | 1 + plugin-api/build.gradle | 2 +- .../storage/KeyValueStorageFactory.java | 24 +- .../storage}/SegmentedKeyValueStorage.java | 98 ++---- .../SegmentedKeyValueStorageTransaction.java | 55 ++++ .../storage/SnappableKeyValueStorage.java | 2 +- .../storage/SnappedKeyValueStorage.java | 4 +- .../RocksDBKeyValuePrivacyStorageFactory.java | 24 ++ .../RocksDBKeyValueStorageFactory.java | 83 ++--- .../storage/rocksdb/RocksDBTransaction.java | 121 +++++++ ...imisticRocksDBColumnarKeyValueStorage.java | 26 +- .../RocksDBColumnarKeyValueSnapshot.java | 59 ++-- .../RocksDBColumnarKeyValueStorage.java | 184 ++++------- .../segmented/RocksDBSnapshotTransaction.java | 46 +-- ...ctionDBRocksDBColumnarKeyValueStorage.java | 15 +- ...ksDBKeyValuePrivacyStorageFactoryTest.java | 5 +- .../RocksDBKeyValueStorageFactoryTest.java | 5 +- ...nDBRocksDBColumnarKeyValueStorageTest.java | 10 +- .../RocksDBColumnarKeyValueStorageTest.java | 115 +++---- ...nDBRocksDBColumnarKeyValueStorageTest.java | 10 +- .../kvstore/InMemoryKeyValueStorage.java | 247 +++----------- .../kvstore/InMemoryStoragePlugin.java | 38 ++- ...StorageTransactionValidatorDecorator.java} | 18 +- .../kvstore/LayeredKeyValueStorage.java | 99 ++++-- .../LimitedInMemoryKeyValueStorage.java | 3 +- .../SegmentedInMemoryKeyValueStorage.java | 301 ++++++++++++++++++ .../SegmentedKeyValueStorageAdapter.java | 107 ++++--- ...StorageTransactionValidatorDecorator.java} | 36 +-- ...ppableSegmentedKeyValueStorageAdapter.java | 67 ---- 52 files changed, 1398 insertions(+), 1117 deletions(-) create mode 100644 ethereum/evmtool/txs.rlp rename {services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore => plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage}/SegmentedKeyValueStorage.java (51%) create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/storage/SegmentedKeyValueStorageTransaction.java create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBTransaction.java rename services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/{KeyValueStorageTransactionTransitionValidatorDecorator.java => KeyValueStorageTransactionValidatorDecorator.java} (69%) create mode 100644 services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SegmentedInMemoryKeyValueStorage.java rename services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/{SegmentedKeyValueStorageTransactionTransitionValidatorDecorator.java => SegmentedKeyValueStorageTransactionValidatorDecorator.java} (64%) delete mode 100644 services/kvstore/src/main/java/org/hyperledger/besu/services/kvstore/SnappableSegmentedKeyValueStorageAdapter.java 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/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/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/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/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 a55ad27f20a..b051b0f7976 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 @@ -31,7 +31,7 @@ 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.segmented.OptimisticRocksDBColumnarKeyValueStorage; -import org.hyperledger.besu.services.kvstore.SnappableSegmentedKeyValueStorageAdapter; +import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; import java.io.IOException; import java.nio.file.Files; @@ -70,7 +70,7 @@ public static OperationBenchmarkHelper create() throws IOException { RocksDBMetricsFactory.PUBLIC_ROCKS_DB_METRICS); final KeyValueStorage keyValueStorage = - new SnappableSegmentedKeyValueStorageAdapter<>( + new SegmentedKeyValueStorageAdapter( KeyValueSegmentIdentifier.BLOCKCHAIN, optimisticRocksDBColumnarKeyValueStorage); final ExecutionContextTestFixture executionContext = 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..2e89e0f791a 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()); } @@ -223,10 +211,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..04c4aefe66d 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,8 +159,8 @@ 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)); } @@ -186,8 +181,8 @@ public Optional getAccountStorageTrieNode( if (maybeNodeHash.filter(hash -> hash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)).isPresent()) { 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)); } @@ -204,15 +199,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 +240,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 +265,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 +293,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 +308,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 +344,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 +374,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 +391,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 +415,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 +433,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 +469,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 +519,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..9991ee994e1 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; @@ -182,7 +185,11 @@ private Hash calculateRootHash( bonsaiUpdater -> { accountTrie.commit( (location, hash, value) -> - writeTrieNode(bonsaiUpdater.getTrieBranchStorageTransaction(), location, value)); + writeTrieNode( + TRIE_BRANCH_STORAGE, + bonsaiUpdater.getWorldStateTransaction(), + location, + value)); }); final Bytes32 rootHash = accountTrie.getRootHash(); return Hash.wrap(rootHash); @@ -391,17 +398,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 +461,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()); } @@ -484,8 +515,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( 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/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/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java index 8f717e7de31..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,10 +42,11 @@ 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; @@ -59,36 +63,40 @@ @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; @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( @@ -145,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)); @@ -170,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 = @@ -201,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(); @@ -242,9 +246,8 @@ public void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState // TODO: refactor to test original intent @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(); @@ -270,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()))) @@ -281,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 6652442a30a..5fd11880b29 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; @@ -210,8 +211,8 @@ public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode(final FlatDbMod // 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,8 +241,8 @@ public void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode(final FlatDbMod // 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 @@ -270,8 +271,8 @@ public void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flat // 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); @@ -317,8 +318,8 @@ public void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode fla // 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 @@ -348,8 +349,8 @@ public void getStorage_loadFromTrieWhenEmptyWithFullMode(final FlatDbMode flatDb // 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 @@ -416,7 +417,9 @@ public void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flat 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(); 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 71479416740..e3f0ffaa74c 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,7 +41,6 @@ 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; @@ -59,19 +58,19 @@ 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 = @@ -133,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 = @@ -160,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 @@ -329,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/worldstate/MarkSweepPrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/worldstate/MarkSweepPrunerTest.java index 7e0af71fe7d..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 @@ -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/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 cd0d515e5d3..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(); 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/plugin-api/build.gradle b/plugin-api/build.gradle index 5fa8a997c10..810760091d1 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -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 = 'DyHMAiRn7aROnI2DCHrrkhU9szOs+NbI6FAxELrwEGQ=' + knownHash = 'Tv7ZbXqvytaHJFsEtGuGFrhITRAlJ02T4/54GjhEI5Y=' } check.dependsOn('checkAPIChanges') 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/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 042fdd15d3f..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; @@ -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(); 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 45eefc67182..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; @@ -31,7 +30,6 @@ import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.RocksDBColumnarKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.rocksdb.segmented.TransactionDBRocksDBColumnarKeyValueStorage; import org.hyperledger.besu.services.kvstore.SegmentedKeyValueStorageAdapter; -import org.hyperledger.besu.services.kvstore.SnappableSegmentedKeyValueStorageAdapter; import java.io.IOException; import java.nio.file.Files; @@ -44,7 +42,10 @@ 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); @@ -55,31 +56,30 @@ public class RocksDBKeyValueStorageFactory implements KeyValueStorageFactory { private final int defaultVersion; private Integer databaseVersion; - private Boolean isSegmentIsolationSupported; private RocksDBColumnarKeyValueStorage segmentedStorage; 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; @@ -89,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); } /** @@ -151,12 +156,32 @@ 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. @@ -164,7 +189,7 @@ public KeyValueStorage create( case 1, 2 -> { if (segmentedStorage == null) { final List segmentsForVersion = - segments.stream() + configuredSegments.stream() .filter(segmentId -> segmentId.includeInDatabaseVersion(databaseVersion)) .collect(Collectors.toList()); if (isForestStorageFormat) { @@ -187,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( @@ -229,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)) @@ -278,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/RocksDBTransaction.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBTransaction.java new file mode 100644 index 00000000000..53f7a8fedac --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBTransaction.java @@ -0,0 +1,121 @@ +/* + * 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; + +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.SegmentedKeyValueStorageTransaction; + +import java.util.function.Function; + +import org.rocksdb.ColumnFamilyHandle; +import org.rocksdb.RocksDBException; +import org.rocksdb.Transaction; +import org.rocksdb.WriteOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** The RocksDb transaction. */ +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 + */ + 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 SegmentIdentifier segmentId, final byte[] key, final byte[] value) { + try (final OperationTimer.TimingContext ignored = metrics.getWriteLatency().startTimer()) { + innerTx.put(columnFamilyMapper.apply(segmentId), key, value); + } catch (final RocksDBException e) { + if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { + logger.error(e.getMessage()); + System.exit(0); + } + throw new StorageException(e); + } + } + + @Override + public void remove(final SegmentIdentifier segmentId, final byte[] key) { + try (final OperationTimer.TimingContext ignored = metrics.getRemoveLatency().startTimer()) { + innerTx.delete(columnFamilyMapper.apply(segmentId), key); + } catch (final RocksDBException e) { + if (e.getMessage().contains(NO_SPACE_LEFT_ON_DEVICE)) { + logger.error(e.getMessage()); + System.exit(0); + } + throw new StorageException(e); + } + } + + @Override + public 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)) { + logger.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)) { + logger.error(e.getMessage()); + System.exit(0); + } + throw new StorageException(e); + } finally { + close(); + } + } + + private void close() { + innerTx.close(); + options.close(); + } +} 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/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 c72052d7604..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; @@ -43,8 +44,8 @@ public class RocksDBKeyValuePrivacyStorageFactoryTest { @Mock private BesuConfiguration commonConfiguration; @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 shouldDetectVersion1DatabaseIfNoMetadataFileFound() throws Exception { 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 9061e28c3ec..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,6 +26,7 @@ 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; @@ -48,8 +49,8 @@ public class RocksDBKeyValueStorageFactoryTest { @Mock private BesuConfiguration commonConfiguration; @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 { 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 3a292acfec3..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 @@ -17,10 +17,9 @@ 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; @@ -35,8 +34,7 @@ public class OptimisticTransactionDBRocksDBColumnarKeyValueStorageTest extends RocksDBColumnarKeyValueStorageTest { @Override - protected SegmentedKeyValueStorage createSegmentedStore() - throws Exception { + protected SegmentedKeyValueStorage createSegmentedStore() throws Exception { return new OptimisticRocksDBColumnarKeyValueStorage( new RocksDBConfigurationBuilder() .databaseDir(Files.createTempDirectory("segmentedStore")) @@ -48,7 +46,7 @@ protected SegmentedKeyValueStorage createSegmentedStor } @Override - protected SegmentedKeyValueStorage createSegmentedStore( + protected SegmentedKeyValueStorage createSegmentedStore( final Path path, final List segments, final List ignorableSegments) { @@ -61,7 +59,7 @@ protected SegmentedKeyValueStorage createSegmentedStor } @Override - protected SegmentedKeyValueStorage createSegmentedStore( + protected SegmentedKeyValueStorage createSegmentedStore( final Path path, final MetricsSystem metricsSystem, final List segments, 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 7605b919e16..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 @@ -33,10 +33,9 @@ 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; @@ -67,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(); }; @@ -99,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(); @@ -121,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(); } @@ -165,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); @@ -200,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), @@ -218,7 +209,7 @@ public void dbShouldNotIgnoreExperimentalSegmentsIfExisted(@TempDir final Path t 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), @@ -248,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), @@ -300,12 +291,11 @@ public void createStoreMustCreateMetrics() throws Exception { // Actual call - final SegmentedKeyValueStorage store = + final SegmentedKeyValueStorage store = createSegmentedStore( folder, metricsSystemMock, List.of(TestSegment.FOO), List.of(TestSegment.EXPERIMENTAL)); - KeyValueStorage keyValueStorage = - new SnappableSegmentedKeyValueStorageAdapter<>(TestSegment.FOO, store); + KeyValueStorage keyValueStorage = new SegmentedKeyValueStorageAdapter(TestSegment.FOO, store); // Assertions assertThat(keyValueStorage).isNotNull(); @@ -389,15 +379,14 @@ public boolean containsStaticData() { } } - protected abstract SegmentedKeyValueStorage createSegmentedStore() - throws Exception; + protected abstract SegmentedKeyValueStorage createSegmentedStore() throws Exception; - protected abstract SegmentedKeyValueStorage createSegmentedStore( + 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, @@ -405,6 +394,6 @@ protected abstract SegmentedKeyValueStorage createSegm @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/TransactionDBRocksDBColumnarKeyValueStorageTest.java b/plugins/rocksdb/src/test/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorageTest.java index 3d880fbc770..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 @@ -17,10 +17,9 @@ 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; @@ -34,8 +33,7 @@ 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), @@ -45,7 +43,7 @@ protected SegmentedKeyValueStorage createSegmentedStor } @Override - protected SegmentedKeyValueStorage createSegmentedStore( + protected SegmentedKeyValueStorage createSegmentedStore( final Path path, final List segments, final List ignorableSegments) { @@ -58,7 +56,7 @@ protected SegmentedKeyValueStorage createSegmentedStor } @Override - protected SegmentedKeyValueStorage createSegmentedStore( + protected SegmentedKeyValueStorage createSegmentedStore( final Path path, final MetricsSystem metricsSystem, final List segments, 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(); - } -} From e92e5de8f63eac7667a039cf8060e927b1b9cf7a Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Mon, 31 Jul 2023 15:36:54 +1000 Subject: [PATCH 31/51] Make smart contract permissioning features work with london fork (#5727) * Make smart contract permissioning features work with london fork Override the transactionSimulator's default TransactionValidationParams with one that allows for exceeding the account balance (which effectively zeros the baseFee). This mimics the way that eth_estimateGas and eth_call are implemented. Similar change to #5277 Update ATs to use londonBlock (existing genesis allocs necessitate zeroBaseFee as well) Signed-off-by: Simon Dudley * changelog Signed-off-by: Simon Dudley --------- Signed-off-by: Simon Dudley --- CHANGELOG.md | 1 + .../permissioning/simple_permissioning_genesis.json | 3 ++- .../permissioning/simple_permissioning_ibft_genesis.json | 3 ++- .../permissioning/simple_permissioning_v2_genesis.json | 3 ++- .../besu/ethereum/transaction/TransactionSimulator.java | 6 +++++- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e95780060b7..55939aebff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Additions and Improvements ### Bug Fixes +- Make smart contract permissioning features work with london fork [#5727](https://github.com/hyperledger/besu/pull/5727) ### Download Links 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/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 9a76eafee7b..22c4ac4554f 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 @@ -28,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; @@ -102,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()); From 52342e550c7b928d767ced1f053365baff862b97 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 31 Jul 2023 12:39:41 +0200 Subject: [PATCH 32/51] Correctly cache the TransactionValidator instance on creation (#5726) Signed-off-by: Fabio Di Fabio --- .../mainnet/TransactionValidatorFactory.java | 53 +++++++------------ .../TransactionValidationFactoryTest.java | 52 ++++++++++++++++++ 2 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationFactoryTest.java 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 index f21be83d0e1..e89ca469a8a 100644 --- 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 @@ -24,17 +24,12 @@ import java.util.Optional; import java.util.Set; +import com.google.common.base.Supplier; import com.google.common.base.Suppliers; public class TransactionValidatorFactory { - private final GasCalculator gasCalculator; - private final GasLimitCalculator gasLimitCalculator; - private final FeeMarket feeMarket; - private final boolean disallowSignatureMalleability; - private final Optional chainId; - private final Set acceptedTransactionTypes; - private final int maxInitcodeSize; - private Optional permissionTransactionFilter = Optional.empty(); + + private volatile Supplier transactionValidatorSupplier; public TransactionValidatorFactory( final GasCalculator gasCalculator, @@ -73,37 +68,29 @@ public TransactionValidatorFactory( final Optional chainId, final Set acceptedTransactionTypes, final int maxInitcodeSize) { - this.gasCalculator = gasCalculator; - this.gasLimitCalculator = gasLimitCalculator; - this.feeMarket = feeMarket; - this.disallowSignatureMalleability = checkSignatureMalleability; - this.chainId = chainId; - this.acceptedTransactionTypes = acceptedTransactionTypes; - this.maxInitcodeSize = maxInitcodeSize; + + this.transactionValidatorSupplier = + Suppliers.memoize( + () -> + new MainnetTransactionValidator( + gasCalculator, + gasLimitCalculator, + feeMarket, + checkSignatureMalleability, + chainId, + acceptedTransactionTypes, + maxInitcodeSize)); } public void setPermissionTransactionFilter( final PermissionTransactionFilter permissionTransactionFilter) { - this.permissionTransactionFilter = Optional.of(permissionTransactionFilter); + final TransactionValidator baseTxValidator = transactionValidatorSupplier.get(); + transactionValidatorSupplier = + Suppliers.memoize( + () -> new PermissionTransactionValidator(baseTxValidator, permissionTransactionFilter)); } public TransactionValidator get() { - return Suppliers.memoize(this::createTransactionValidator).get(); - } - - private TransactionValidator createTransactionValidator() { - final TransactionValidator baseValidator = - new MainnetTransactionValidator( - gasCalculator, - gasLimitCalculator, - feeMarket, - disallowSignatureMalleability, - chainId, - acceptedTransactionTypes, - maxInitcodeSize); - if (permissionTransactionFilter.isPresent()) { - return new PermissionTransactionValidator(baseValidator, permissionTransactionFilter.get()); - } - return baseValidator; + return transactionValidatorSupplier.get(); } } 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()); + } +} From 7738a6a2aa24228994e2d24fab769353bc592b20 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 31 Jul 2023 13:42:01 -0600 Subject: [PATCH 33/51] Reference tests 12.3 (#5733) Update Reference Tests to 12.3 * fix decoding error * add ignored field * update module Signed-off-by: Danno Ferrin --- ethereum/referencetests/build.gradle | 2 +- .../BlockchainReferenceTestCaseSpec.java | 11 ++++++----- .../src/reference-test/external-resources | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 1aa1e2a2651..5f4e3901c56 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -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 { 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 3171a7eee14..8e5d0156502 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 @@ -189,7 +189,7 @@ public ReferenceTestBlockHeader( Hash.fromHexString(mixHash), // mixHash Bytes.fromHexStringLenient(nonce).toLong(), withdrawalsRoot != null ? Hash.fromHexString(withdrawalsRoot) : null, - dataGasUsed != null ? Long.parseLong(dataGasUsed) : 0, + dataGasUsed != null ? Long.decode(dataGasUsed) : 0, excessDataGas != null ? DataGas.fromHexString(excessDataGas) : null, depositsRoot != null ? Hash.fromHexString(depositsRoot) : null, new BlockHeaderFunctions() { @@ -207,6 +207,10 @@ public ParsedExtraData parseExtraData(final BlockHeader header) { } @JsonIgnoreProperties({ + "blocknumber", + "chainname", + "chainnetwork", + "expectException", "expectExceptionByzantium", "expectExceptionConstantinople", "expectExceptionConstantinopleFix", @@ -215,11 +219,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/reference-test/external-resources b/ethereum/referencetests/src/reference-test/external-resources index 04f338a6e67..06e276776bc 160000 --- a/ethereum/referencetests/src/reference-test/external-resources +++ b/ethereum/referencetests/src/reference-test/external-resources @@ -1 +1 @@ -Subproject commit 04f338a6e673a6b4d906ec9d6d2bc939309357a5 +Subproject commit 06e276776bc87817c38f6efb492bf6f4527fa904 From 2969e7a28a7fe569272aa9b7ee2fd9b9062934bc Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 1 Aug 2023 12:31:46 +0200 Subject: [PATCH 34/51] Return all not selected transactions, not only invalid ones. (#5711) This way it is possible for the caller to have more data about the selection process. Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 7 +- .../BlockTransactionSelector.java | 131 ++++++++-------- .../AbstractBlockTransactionSelectorTest.java | 143 +++++++++--------- ...FeeMarketBlockTransactionSelectorTest.java | 17 ++- plugin-api/build.gradle | 2 +- .../data/TransactionSelectionResult.java | 9 ++ 6 files changed, 168 insertions(+), 141 deletions(-) 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 dead80c5a46..ceb6061b717 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 @@ -240,7 +240,7 @@ protected BlockCreationResult createBlock( .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()) @@ -264,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); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 6675973a43d..efce946ed02 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -72,6 +72,7 @@ *

  • A 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 @@ -80,21 +81,21 @@ public class BlockTransactionSelector { 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 Map invalidTransactions = new HashMap<>(); - private final List selectionResults = Lists.newArrayList(); + private final Map notSelectedTransactions = + new HashMap<>(); private long cumulativeGasUsed = 0; private long cumulativeDataGasUsed = 0; - private void update( + private void updateSelected( final Transaction transaction, final TransactionReceipt receipt, final long gasUsed, final long dataGasUsed) { - transactions.add(transaction); + selectedTransactions.add(transaction); transactionsByType .computeIfAbsent(transaction.getType(), type -> new ArrayList<>()) .add(transaction); @@ -105,19 +106,19 @@ private void update( .setMessage( "New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}") .addArgument(transaction::toTraceLog) - .addArgument(transactions::size) + .addArgument(selectedTransactions::size) .addArgument(cumulativeGasUsed) .addArgument(cumulativeDataGasUsed) .log(); } - private void updateWithInvalidTransaction( - final Transaction transaction, final TransactionInvalidReason invalidReason) { - invalidTransactions.put(transaction, invalidReason); + 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) { @@ -136,39 +137,27 @@ public long getCumulativeDataGasUsed() { return cumulativeDataGasUsed; } - public Map getInvalidTransactions() { - return invalidTransactions; - } - - 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(", "))); @@ -186,15 +175,19 @@ 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); + && 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, + cumulativeDataGasUsed); } public String toTraceLog() { @@ -202,13 +195,20 @@ public String toTraceLog() { + cumulativeGasUsed + ", cumulativeDataGasUsed=" + cumulativeDataGasUsed - + ", transactions=" - + transactions.stream().map(Transaction::toTraceLog).collect(Collectors.joining("; ")); + + ", 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; @@ -224,7 +224,6 @@ public String toTraceLog() { private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; private final TransactionSelector transactionSelector; - private final TransactionSelectionResults transactionSelectionResults = new TransactionSelectionResults(); @@ -259,13 +258,12 @@ public BlockTransactionSelector( 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() { @@ -276,7 +274,9 @@ public TransactionSelectionResults buildTransactionListForBlock() { transactionPool.selectTransactions( pendingTransaction -> { final var res = evaluateTransaction(pendingTransaction); - transactionSelectionResults.addSelectionResult(res); + if (!res.selected()) { + transactionSelectionResults.updateNotSelected(pendingTransaction, res); + } return res; }); LOG.atTrace() @@ -294,8 +294,12 @@ public TransactionSelectionResults buildTransactionListForBlock() { */ public TransactionSelectionResults evaluateTransactions(final List transactions) { transactions.forEach( - transaction -> - transactionSelectionResults.addSelectionResult(evaluateTransaction(transaction))); + transaction -> { + final var res = evaluateTransaction(transaction); + if (!res.selected()) { + transactionSelectionResults.updateNotSelected(transaction, res); + } + }); return transactionSelectionResults; } @@ -360,16 +364,13 @@ private TransactionSelectionResult evaluateTransaction(final Transaction transac 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)) { @@ -380,21 +381,23 @@ private TransactionSelectionResult evaluateTransaction(final Transaction transac final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); - transactionSelectionResults.update(transaction, receipt, gasUsedByTransaction, dataGasUsed); + transactionSelectionResults.updateSelected( + transaction, receipt, gasUsedByTransaction, dataGasUsed); LOG.atTrace() .setMessage("Selected {} for block creation") .addArgument(transaction::toTraceLog) .log(); + + return TransactionSelectionResult.SELECTED; } - return txSelectionResult; - } else { - transactionSelectionResults.updateWithInvalidTransaction( - transaction, effectiveResult.getValidationResult().getInvalidReason()); - 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) { 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 517e3a79cd1..e8d008df890 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,6 +15,7 @@ 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; @@ -75,7 +76,6 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -195,19 +195,19 @@ 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() { + 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(500_000); final Address miningBeneficiary = AddressHelpers.ofValue(1); @@ -224,14 +224,14 @@ 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(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, Wei.of(7), 100_000); @@ -261,8 +261,16 @@ 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_000); } @@ -293,48 +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_000); // Ensure receipts have the correct cumulative gas - Assertions.assertThat(results.getReceipts().get(0).getCumulativeGasUsed()).isEqualTo(100_000); - Assertions.assertThat(results.getReceipts().get(1).getCumulativeGasUsed()).isEqualTo(200_000); - Assertions.assertThat(results.getReceipts().get(2).getCumulativeGasUsed()).isEqualTo(300_000); - } - - @Test - public void useSingleGasSpaceForAllTransactions() { - final ProcessableBlockHeader blockHeader = createBlock(300_000); - - final Address miningBeneficiary = AddressHelpers.ofValue(1); - - final BlockTransactionSelector selector = - createBlockSelector( - transactionProcessor, - blockHeader, - Wei.ZERO, - miningBeneficiary, - Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT); - - // this should fill up all the block space - final Transaction fillingLegacyTx = createTransaction(0, Wei.of(10), 300_000); - - ensureTransactionIsValid(fillingLegacyTx); - - // so we shouldn't include this - final Transaction extraEIP1559Tx = createEIP1559Transaction(0, Wei.of(10), Wei.of(10), 50_000); - - ensureTransactionIsValid(extraEIP1559Tx); - - transactionPool.addRemoteTransactions(List.of(fillingLegacyTx, extraEIP1559Tx)); - 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 @@ -369,9 +351,9 @@ public void transactionTooLargeForBlockDoesNotPreventMoreBeingAddedIfBlockOccupa 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[2]); + assertThat(results.getSelectedTransactions()).containsExactly(txs[0], txs[2]); + assertThat(results.getNotSelectedTransactions()) + .containsOnly(entry(txs[1], TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_GAS)); } @Test @@ -408,11 +390,9 @@ public void transactionSelectionStopsWhenSufficientBlockOccupancyIsReached() { 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 @@ -460,9 +440,17 @@ public void transactionSelectionStopsWhenBlockIsFull() { 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,8 +496,14 @@ public void transactionSelectionStopsWhenRemainingGasIsNotEnoughForAnyMoreTransa 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); } @@ -536,12 +530,18 @@ public void shouldDiscardTransactionsThatFailValidation() { transactionPool.addRemoteTransactions(List.of(validTransaction, invalidTransaction)); - selector.buildTransactionListForBlock(); + final BlockTransactionSelector.TransactionSelectionResults results = + selector.buildTransactionListForBlock(); - Assertions.assertThat(transactionPool.getTransactionByHash(validTransaction.getHash())) - .isPresent(); - Assertions.assertThat(transactionPool.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 @@ -586,9 +586,11 @@ public void transactionSelectionPluginShouldWork() { assertThat(transactionPool.getTransactionByHash(notSelectedTransient.getHash())).isPresent(); assertThat(transactionPool.getTransactionByHash(notSelectedInvalid.getHash())).isNotPresent(); - assertThat(transactionSelectionResults.getTransactions()).contains(selected); - assertThat(transactionSelectionResults.getTransactions()).doesNotContain(notSelectedTransient); - assertThat(transactionSelectionResults.getTransactions()).doesNotContain(notSelectedInvalid); + assertThat(transactionSelectionResults.getSelectedTransactions()).containsOnly(selected); + assertThat(transactionSelectionResults.getNotSelectedTransactions()) + .containsOnly( + entry(notSelectedTransient, TransactionSelectionResult.invalidTransient("transient")), + entry(notSelectedInvalid, TransactionSelectionResult.invalid("invalid"))); } @Test @@ -613,9 +615,14 @@ public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - Assertions.assertThat(transactionPool.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( 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 bb6701fc0f7..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,6 +15,7 @@ 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 org.hyperledger.besu.config.GenesisConfigFile; @@ -36,6 +37,7 @@ 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.time.ZoneId; @@ -116,7 +118,9 @@ public void eip1559TransactionCurrentGasPriceLessThanMinimumIsSkippedAndKeptInTh final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(0); + assertThat(results.getSelectedTransactions()).isEmpty(); + assertThat(results.getNotSelectedTransactions()) + .containsOnly(entry(tx, TransactionSelectionResult.CURRENT_TX_PRICE_BELOW_MIN)); assertThat(transactionPool.count()).isEqualTo(1); } @@ -144,8 +148,8 @@ public void eip1559TransactionCurrentGasPriceGreaterThanMinimumIsSelected() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(1); - assertThat(transactionPool.count()).isEqualTo(1); + assertThat(results.getSelectedTransactions()).containsExactly(tx); + assertThat(results.getNotSelectedTransactions()).isEmpty(); } @Test @@ -174,8 +178,8 @@ public void eip1559LocalTransactionCurrentGasPriceLessThanMinimumIsSelected() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions().size()).isEqualTo(1); - assertThat(transactionPool.count()).isEqualTo(1); + assertThat(results.getSelectedTransactions()).containsExactly(tx); + assertThat(results.getNotSelectedTransactions()).isEmpty(); } @Test @@ -207,7 +211,8 @@ public void transactionFromSameSenderWithMixedTypes() { final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); - assertThat(results.getTransactions()) + assertThat(results.getSelectedTransactions()) .containsExactly(txFrontier1, txLondon1, txFrontier2, txLondon2); + assertThat(results.getNotSelectedTransactions()).isEmpty(); } } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 810760091d1..dda81e5e282 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -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 = 'Tv7ZbXqvytaHJFsEtGuGFrhITRAlJ02T4/54GjhEI5Y=' + knownHash = 'kmY3fycbIcbEHpf8aezNlZs3M8dD3lDf74lvedkDDu0=' } check.dependsOn('checkAPIChanges') 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(""); From 33751dc50fb8a268e21ef70cf92feae70ba23ded Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 1 Aug 2023 20:56:37 -0600 Subject: [PATCH 35/51] Address import performance issues (#5734) * ensure we are on a single tuweni version * factor out an unneeded concatenate Signed-off-by: Danno Ferrin --- .../besu/ethereum/core/encoding/TransactionEncoder.java | 8 +++++--- ethereum/p2p/build.gradle | 8 +++++++- 2 files changed, 12 insertions(+), 4 deletions(-) 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 4a0f1f02257..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 @@ -20,6 +20,7 @@ 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; @@ -76,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(); } } diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index ed2f9aa1e0e..dccbe0fb877 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -62,7 +62,13 @@ dependencies { 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') From 5f47188152b7ed32948ba0fb280b9eefd32d11d7 Mon Sep 17 00:00:00 2001 From: George Tebrean <99179176+gtebrean@users.noreply.github.com> Date: Wed, 2 Aug 2023 06:37:25 +0300 Subject: [PATCH 36/51] Add type to PendingTransactionDetail (#5729) * add type * update changelog --------- Signed-off-by: George Tebrean Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 1 + .../pending/PendingTransactionDetailResult.java | 12 ++++++++++++ .../api/jsonrpc/SimpleTestTransactionBuilder.java | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55939aebff8..a49da2ba244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### 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) ### Download Links 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/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)); From ec6a6b1b73751575e3657eff2b837d7083071f37 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 2 Aug 2023 08:21:21 -0600 Subject: [PATCH 37/51] Migrate to blobGas in execution-spec-tests (#5745) Execution-spec-tests migrated from DataGas to BlobGas and checks for its inclusion in tests now. Add needed support. Signed-off-by: Danno Ferrin --- .../hyperledger/besu/evmtool/T8nExecutor.java | 29 +++++--- .../besu/evmtool/T8nServerSubCommand.java | 14 +++- .../t8n/cancun-6780-selfdestruct-sweep.json | 8 ++- .../t8n/cancun-6780-selfdestruct-to-self.json | 72 ++++++++++--------- .../cancun-6780-selfdestruct-transient.json | 8 ++- .../besu/evmtool/t8n/cancun-blobs-per-tx.json | 10 +-- .../referencetests/ReferenceTestEnv.java | 47 +++++++----- 7 files changed, 117 insertions(+), 71 deletions(-) diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index 8fc78eb2845..0eee93193b8 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -81,7 +81,7 @@ public class T8nExecutor { - record RejectedTransaction(int index, String error) {} + public record RejectedTransaction(int index, String error) {} protected static List extractTransactions( final PrintWriter out, @@ -128,9 +128,9 @@ protected static List extractTransactions( if (txNode.has("maxFeePerGas")) { builder.maxFeePerGas(Wei.fromHexString(txNode.get("maxFeePerGas").textValue())); } - if (txNode.has("maxFeePerDataGas")) { + if (txNode.has("maxFeePerBlobGas")) { builder.maxFeePerDataGas( - Wei.fromHexString(txNode.get("maxFeePerDataGas").textValue())); + Wei.fromHexString(txNode.get("maxFeePerBlobGas").textValue())); } if (txNode.has("to")) { @@ -251,8 +251,10 @@ 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().dataPricePerGas(DataGas.ZERO); + final Wei blobGasPrice = + protocolSpec + .getFeeMarket() + .dataPricePerGas(blockHeader.getExcessDataGas().orElse(DataGas.ZERO)); List receipts = new ArrayList<>(); List invalidTransactions = new ArrayList<>(rejections); @@ -279,7 +281,7 @@ static T8nResult runTest( false, TransactionValidationParams.processingBlock(), tracer, - dataGasPrice); + blobGasPrice); tracerManager.disposeTracer(tracer); } catch (Exception e) { throw new RuntimeException(e); @@ -391,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()); @@ -401,6 +403,17 @@ static T8nResult runTest( blockHeader .getWithdrawalsRoot() .ifPresent(wr -> resultObject.put("withdrawalsRoot", wr.toHexString())); + blockHeader + .getDataGasUsed() + .ifPresentOrElse( + bgu -> resultObject.put("blobGasUsed", Bytes.ofUnsignedLong(bgu).toQuantityHexString()), + () -> + blockHeader + .getExcessDataGas() + .ifPresent(ebg -> resultObject.put("blobGasUsed", "0x0"))); + blockHeader + .getExcessDataGas() + .ifPresent(ebg -> resultObject.put("currentExcessBlobGas", ebg.toShortHexString())); ObjectNode allocObject = objectMapper.createObjectNode(); worldState @@ -411,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 fc1c08ad5c9..73e20be247e 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 @@ -26,6 +26,8 @@ import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; import org.hyperledger.besu.util.LogConfigurator; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -168,8 +170,16 @@ public void disposeTracer(final OperationTracer tracer) { req.response().setStatusCode(500).end(e.getMessage()); } } catch (Throwable t) { - t.printStackTrace(); - throw 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()); } } 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 index 668434d98ec..bc7d113ec79 100644 --- 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 @@ -60,8 +60,8 @@ "ommers": [], "withdrawals": [], "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "parentDataGasUsed": "0", - "parentExcessDataGas": "0" + "parentBlobGasUsed": "0", + "parentExcessBlobGas": "0" } }, "stdout": { @@ -108,7 +108,9 @@ "currentDifficulty": null, "gasUsed": "0x127bb", "currentBaseFee": "0x7", - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + "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 index 20314f7f95a..7d8907d9bfb 100644 --- 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 @@ -62,52 +62,54 @@ "ommers": [], "withdrawals": [], "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "parentDataGasUsed": "0", - "parentExcessDataGas": "0" + "parentBlobGasUsed": "0", + "parentExcessBlobGas": "0" } }, "stdout": { - "alloc" : { - "0x095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "code" : "0x3060005530ff00", - "storage" : { - "0x0000000000000000000000000000000000000000000000000000000000000000" : "0x000000000000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d87" + "alloc": { + "0x095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "code": "0x3060005530ff00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d87" }, - "balance" : "0xde0b6b3a76586a0" + "balance": "0xde0b6b3a76586a0" }, - "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { - "balance" : "0x233c1" + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x233c1" }, - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "0xde0b6b3a75b2232", - "nonce" : "0x1" + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0xde0b6b3a75b2232", + "nonce": "0x1" } }, - "body" : "0xf865f863800a830f424094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ca07bb4986663aec020c016ea3db37ba36e62e9c7d355dc8ed8566b20ce7452b600a07da62397d8a969f674442837f419001f2671df0f19a45586ed3acfd93e819d82", - "result" : { - "stateRoot" : "0xddd3a541e86e2dd0293959736de63e1fad74ae95149f34740b1173378e82527a", - "txRoot" : "0x0cbd46498d79551ba2f4237443d408194f7493f1fd567dbeaf1d53b41b41485a", - "receiptsRoot" : "0xbc67bed8ee77b1d9dd8eb6d6e55abd11e49c50e16832f0c350ae07027c859f19", - "logsHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "receipts" : [ + "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" + "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" + "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 index 952ca1d0b65..1860990b0f7 100644 --- 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 @@ -54,8 +54,8 @@ "ommers": [], "withdrawals": [], "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "parentDataGasUsed": "0", - "parentExcessDataGas": "0" + "parentBlobGasUsed": "0", + "parentExcessBlobGas": "0" } }, "stdout": { @@ -92,7 +92,9 @@ "currentDifficulty": null, "gasUsed": "0x181c6", "currentBaseFee": "0x7", - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + "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 index ac323e74a01..b2ed324b3d6 100644 --- 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 @@ -36,7 +36,7 @@ "input": "0x", "to": "0x0000000000000000000000000000000000000100", "accessList": [], - "maxFeePerDataGas": "0x1", + "maxFeePerBlobGas": "0x1", "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "blobVersionedHashes": [ "0x0100000000000000000000000000000000000000000000000000000000000000" @@ -65,8 +65,8 @@ "ommers": [], "withdrawals": [], "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "currentExcessDataGas": "0", - "currentDataGasUsed": "0" + "currentExcessBlobGas": "0", + "currentBlobGasUsed": "0" } }, "stdout": { @@ -109,7 +109,9 @@ "currentDifficulty": null, "gasUsed": "0x5208", "currentBaseFee": "0x7", - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "currentExcessBlobGas": "0x0" } } } \ No newline at end of file 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 14d9b13348b..53aba098c1c 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.DataGas; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -77,9 +78,11 @@ Withdrawal asWithdrawal() { private final Map blockHashes; - private final String parentExcessDataGas; + private final String parentExcessBlobGas; - private final String parentDataGasUsed; + private final String parentBlobGasUsed; + + private final Hash beaconRoot; /** * Public constructor. @@ -111,10 +114,11 @@ public ReferenceTestEnv( @JsonProperty("parentUncleHash") final String _parentUncleHash, @JsonProperty("withdrawals") final List withdrawals, @JsonProperty("blockHashes") final Map blockHashes, - @JsonProperty("currentExcessDataGas") final String currentExcessDataGas, - @JsonProperty("currentDataGasUsed") final String currentDataGasUsed, - @JsonProperty("parentExcessDataGas") final String parentExcessDataGas, - @JsonProperty("parentDataGasUsed") final String parentDataGasUsed) { + @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 @@ -133,8 +137,8 @@ public ReferenceTestEnv( Optional.ofNullable(random).map(Difficulty::fromHexString).orElse(Difficulty.ZERO), 0L, null, // withdrawalsRoot - null, // dataGasUsed - null, // excessDataGas + currentBlobGasUsed == null ? null : Long.decode(currentBlobGasUsed), + currentExcessBlobGas == null ? null : DataGas.fromHexString(currentExcessBlobGas), null, // depositsRoot new MainnetBlockHeaderFunctions()); this.parentDifficulty = parentDifficulty; @@ -142,8 +146,8 @@ public ReferenceTestEnv( this.parentGasUsed = parentGasUsed; this.parentGasLimit = parentGasLimit; this.parentTimestamp = parentTimestamp; - this.parentExcessDataGas = parentExcessDataGas; - this.parentDataGasUsed = parentDataGasUsed; + this.parentExcessBlobGas = parentExcessBlobGas; + this.parentBlobGasUsed = parentBlobGasUsed; this.withdrawals = withdrawals == null ? List.of() @@ -157,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 @@ -206,6 +211,14 @@ public BlockHeader updateFromParentValues(final ProtocolSpec protocolSpec) { .buildBlockHeader(), null))); } + if (excessDataGas == null && parentExcessBlobGas != null && parentBlobGasUsed != null) { + builder.excessDataGas( + DataGas.of( + protocolSpec + .getGasCalculator() + .computeExcessDataGas( + Long.decode(parentExcessBlobGas), Long.decode(parentGasUsed)))); + } return builder.buildBlockHeader(); } @@ -228,9 +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(parentDataGasUsed, that.parentDataGasUsed) - && Objects.equals(parentExcessDataGas, that.parentExcessDataGas) - && 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 @@ -242,8 +256,9 @@ public int hashCode() { parentGasUsed, parentGasLimit, parentTimestamp, - parentDataGasUsed, - parentExcessDataGas, - withdrawals); + parentBlobGasUsed, + parentExcessBlobGas, + withdrawals, + beaconRoot); } } From a46cf27ec5cfee049e627614ab345b0ed4f172c4 Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Fri, 4 Aug 2023 21:50:26 +0100 Subject: [PATCH 38/51] Append ABI-decoded revert reason to message field in error responses (#5706) Signed-off-by: Matthew Whitehead Signed-off-by: Simon Dudley --- CHANGELOG.md | 2 + .../privacy/PrivCallAcceptanceTest.java | 2 +- ethereum/api/build.gradle | 6 + .../internal/response/JsonRpcError.java | 17 ++- .../response/JsonRpcErrorResponse.java | 39 +++++- .../jsonrpc/internal/methods/EthCallTest.java | 125 ++++++++++++++++++ .../internal/methods/EthEstimateGasTest.java | 99 ++++++++++++-- 7 files changed, 272 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a49da2ba244..4986f1e594e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### 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 ### Bug Fixes 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/ethereum/api/build.gradle b/ethereum/api/build.gradle index 5e526239088..d6c230ae018 100644 --- a/ethereum/api/build.gradle +++ b/ethereum/api/build.gradle @@ -72,6 +72,12 @@ dependencies { 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" 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 6c26e8837f0..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 @@ -21,6 +21,7 @@ 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) @@ -28,6 +29,7 @@ public class JsonRpcError { private final int code; private final String message; private final String data; + private String reason; @JsonCreator public JsonRpcError( @@ -41,6 +43,15 @@ public JsonRpcError( 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) { @@ -54,7 +65,7 @@ public int getCode() { @JsonGetter("message") public String getMessage() { - return message; + return (reason == null ? message : message + ": " + reason); } @JsonGetter("data") @@ -72,12 +83,12 @@ public boolean equals(final Object o) { } final JsonRpcError that = (JsonRpcError) o; return code == that.code - && Objects.equals(message, that.message) + && Objects.equals(message.split(":", -1)[0], that.message.split(":", -1)[0]) && Objects.equals(data, that.data); } @Override public int hashCode() { - return Objects.hash(code, message, data); + 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 d2e7fe668e0..8fd311685da 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 @@ -15,12 +15,21 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.response; 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 { @@ -29,6 +38,9 @@ public class JsonRpcErrorResponse implements JsonRpcResponse { 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; @@ -84,8 +96,33 @@ public RpcErrorType getErrorType() { private RpcErrorType findErrorType(final int code, final String message) { return Arrays.stream(RpcErrorType.values()) - .filter(e -> e.getCode() == code && e.getMessage().equals(message)) + .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/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 b3588a6c46c..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 @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; 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; @@ -164,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/EthEstimateGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java index 6b6f9034101..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 @@ -144,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)); @@ -257,9 +257,71 @@ public void shouldReturnErrorWhenTransactionReverted() { final JsonRpcResponse expectedResponse = 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 @@ -304,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)), @@ -339,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; From fb3b262f1bc75a775d4080b4e8d2463041937e67 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 8 Aug 2023 15:58:28 -0600 Subject: [PATCH 39/51] Call operation performance optimizations (#5537) * Call Operation performance improvements - Move values that are the same or shared across the transaction to TxValues record - Move warm and cold storage to undoable sets and tables. - Move transient storage to undoable table. - Move address hashing inside of address with a memoized field. - lazy create EOF return stack Signed-off-by: Danno Ferrin --- .../hyperledger/besu/datatypes/Address.java | 30 ++ .../operations/OperationBenchmarkHelper.java | 10 +- .../besu/ethereum/bonsai/BonsaiAccount.java | 4 +- .../bonsai/BonsaiWorldStateProvider.java | 14 +- .../bonsai/cache/CachedMerkleTrieLoader.java | 9 +- .../cache/CachedWorldStorageManager.java | 15 +- .../bonsai/worldview/BonsaiWorldState.java | 74 ++-- .../BonsaiWorldStateUpdateAccumulator.java | 2 +- .../mainnet/MainnetTransactionProcessor.java | 6 +- .../privacy/PrivateTransactionProcessor.java | 19 +- .../proof/WorldStateProofProvider.java | 4 +- .../ethereum/vm/DebugOperationTracer.java | 9 +- .../worldstate/DefaultMutableWorldState.java | 6 +- .../core/MessageFrameTestFixture.java | 21 +- .../BonsaiWorldStateKeyValueStorageTest.java | 50 +-- .../bonsai/CachedMerkleTrieLoaderTest.java | 27 +- .../proof/WorldStateProofProviderTest.java | 2 +- .../ethereum/vm/DebugOperationTracerTest.java | 8 +- .../vm/EstimateGasOperationTracerTest.java | 13 +- .../CheckpointDownloaderFactory.java | 3 +- .../sync/snapsync/SnapDownloaderFactory.java | 3 +- ...geFlatDatabaseHealingRangeRequestTest.java | 15 +- .../besu/evmtool/EvmToolCommand.java | 11 +- .../besu/evmtool/StateTestSubCommand.java | 24 ++ .../besu/collections/undo/UndoList.java | 317 ++++++++++++++ .../besu/collections/undo/UndoMap.java | 156 +++++++ .../besu/collections/undo/UndoSet.java | 192 +++++++++ .../besu/collections/undo/UndoTable.java | 209 +++++++++ .../collections/undo/UndoableCollection.java | 86 ++++ .../besu/evm/fluent/EVMExecutor.java | 6 +- .../besu/evm/fluent/SimpleAccount.java | 2 +- .../besu/evm/frame/BlockValues.java | 2 +- .../besu/evm/frame/MessageFrame.java | 402 +++++++----------- .../hyperledger/besu/evm/frame/TxValues.java | 63 +++ .../evm/operation/AbstractCallOperation.java | 43 +- .../operation/AbstractCreateOperation.java | 43 +- .../processor/AbstractMessageProcessor.java | 4 +- .../tracing/AccessListOperationTracer.java | 13 +- .../tracing/EstimateGasOperationTracer.java | 10 +- .../besu/evm/tracing/StandardJsonTracer.java | 3 +- .../evm/worldstate/UpdateTrackingAccount.java | 5 +- .../besu/collections/undo/UndoListTest.java | 383 +++++++++++++++++ .../besu/collections/undo/UndoMapTest.java | 269 ++++++++++++ .../besu/collections/undo/UndoSetTest.java | 301 +++++++++++++ .../hyperledger/besu/evm/code/CodeV0Test.java | 3 - .../AbstractCreateOperationTest.java | 6 +- .../evm/operations/Create2OperationTest.java | 23 +- .../evm/operations/CreateOperationTest.java | 38 +- .../operations/SelfDestructOperationTest.java | 4 - .../besu/evm/precompile/Benchmarks.java | 3 - .../besu/evm/testutils/TestCodeExecutor.java | 7 +- .../testutils/TestMessageFrameBuilder.java | 16 - .../besu/evm/toy/EvmToyCommand.java | 17 +- .../hyperledger/besu/evm/toy/ToyAccount.java | 2 +- 54 files changed, 2426 insertions(+), 581 deletions(-) create mode 100644 evm/src/main/java/org/hyperledger/besu/collections/undo/UndoList.java create mode 100644 evm/src/main/java/org/hyperledger/besu/collections/undo/UndoMap.java create mode 100644 evm/src/main/java/org/hyperledger/besu/collections/undo/UndoSet.java create mode 100644 evm/src/main/java/org/hyperledger/besu/collections/undo/UndoTable.java create mode 100644 evm/src/main/java/org/hyperledger/besu/collections/undo/UndoableCollection.java create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java create mode 100644 evm/src/test/java/org/hyperledger/besu/collections/undo/UndoListTest.java create mode 100644 evm/src/test/java/org/hyperledger/besu/collections/undo/UndoMapTest.java create mode 100644 evm/src/test/java/org/hyperledger/besu/collections/undo/UndoSetTest.java 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 8862d9461e2..72f97133eb2 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; @@ -75,6 +80,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. * @@ -237,4 +254,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/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 b051b0f7976..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 @@ -112,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/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/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java index 9991ee994e1..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 @@ -65,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; @@ -112,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; } @@ -127,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()); } /** @@ -182,15 +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( - TRIE_BRANCH_STORAGE, - bonsaiUpdater.getWorldStateTransaction(), - 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); } @@ -234,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); @@ -250,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); @@ -297,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); } @@ -320,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) { @@ -328,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), @@ -341,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); @@ -505,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); } @@ -546,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); } @@ -555,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); } @@ -568,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/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index e65b9ce9eb2..a87a35d7257 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; @@ -350,7 +349,6 @@ public TransactionProcessingResult processTransaction( dataGas); final WorldUpdater worldUpdater = worldState.updater(); - final Deque messageFrameStack = new ArrayDeque<>(); final ImmutableMap.Builder contextVariablesBuilder = ImmutableMap.builder() .put(KEY_IS_PERSISTING_PRIVATE_STATE, isPersistingPrivateState) @@ -362,7 +360,6 @@ public TransactionProcessingResult processTransaction( final MessageFrame.Builder commonMessageFrameBuilder = MessageFrame.builder() - .messageFrameStack(messageFrameStack) .maxStackSize(maxStackSize) .worldUpdater(worldUpdater.updater()) .initialGas(gasAvailable) @@ -372,7 +369,6 @@ public TransactionProcessingResult processTransaction( .value(transaction.getValue()) .apparentValue(transaction.getValue()) .blockValues(blockHeader) - .depth(0) .completer(__ -> {}) .miningBeneficiary(miningBeneficiary) .blockHashLookup(blockHashLookup) @@ -417,8 +413,8 @@ public TransactionProcessingResult processTransaction( .orElse(CodeV0.EMPTY_CODE)) .build(); } + Deque messageFrameStack = initialFrame.getMessageFrameStack(); - messageFrameStack.addFirst(initialFrame); if (initialFrame.getCode().isValid()) { while (!messageFrameStack.isEmpty()) { process(messageFrameStack.peekFirst(), operationTracer); 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 8cd8db2bf49..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 @@ -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; @@ -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/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/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/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/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateKeyValueStorageTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateKeyValueStorageTest.java index 5fd11880b29..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 @@ -66,14 +66,14 @@ public void setUp(final FlatDbMode flatDbMode) { @ParameterizedTest @MethodSource("data") - public void getCode_returnsEmpty(final FlatDbMode flatDbMode) { + void getCode_returnsEmpty(final FlatDbMode flatDbMode) { setUp(flatDbMode); assertThat(storage.getCode(Hash.EMPTY, Hash.EMPTY)).contains(Bytes.EMPTY); } @ParameterizedTest @MethodSource("data") - public void getAccountStateTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { + void getAccountStateTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { setUp(flatDbMode); assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); @@ -81,7 +81,7 @@ public void getAccountStateTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode @ParameterizedTest @MethodSource("data") - public void getAccountStorageTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { + void getAccountStorageTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { setUp(flatDbMode); assertThat( storage.getAccountStorageTrieNode( @@ -91,21 +91,21 @@ public void getAccountStorageTrieNode_returnsEmptyNode(final FlatDbMode flatDbMo @ParameterizedTest @MethodSource("data") - public void getNodeData_returnsEmptyValue(final FlatDbMode flatDbMode) { + void getNodeData_returnsEmptyValue(final FlatDbMode flatDbMode) { setUp(flatDbMode); assertThat(storage.getNodeData(null, null)).isEmpty(); } @ParameterizedTest @MethodSource("data") - public void getNodeData_returnsEmptyNode(final FlatDbMode flatDbMode) { + void getNodeData_returnsEmptyNode(final FlatDbMode flatDbMode) { setUp(flatDbMode); assertThat(storage.getNodeData(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)).isEmpty(); } @ParameterizedTest @MethodSource("data") - public void getCode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + void getCode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { setUp(flatDbMode); storage .updater() @@ -119,7 +119,7 @@ public void getCode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { @ParameterizedTest @MethodSource("data") - public void getCode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + void getCode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { setUp(flatDbMode); final Bytes bytes = Bytes.fromHexString("0x123456"); storage.updater().putCode(Hash.EMPTY, bytes).commit(); @@ -129,7 +129,7 @@ public void getCode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { @ParameterizedTest @MethodSource("data") - public void getAccountStateTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + void getAccountStateTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { setUp(flatDbMode); storage .updater() @@ -145,7 +145,7 @@ public void getAccountStateTrieNode_saveAndGetSpecialValues(final FlatDbMode fla @ParameterizedTest @MethodSource("data") - public void getAccountStateTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + void getAccountStateTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { setUp(flatDbMode); final Bytes location = Bytes.fromHexString("0x01"); final Bytes bytes = Bytes.fromHexString("0x123456"); @@ -157,7 +157,7 @@ public void getAccountStateTrieNode_saveAndGetRegularValue(final FlatDbMode flat @ParameterizedTest @MethodSource("data") - public void getAccountStorageTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { + void getAccountStorageTrieNode_saveAndGetSpecialValues(final FlatDbMode flatDbMode) { setUp(flatDbMode); storage @@ -180,9 +180,9 @@ public void getAccountStorageTrieNode_saveAndGetSpecialValues(final FlatDbMode f @ParameterizedTest @MethodSource("data") - public void getAccountStorageTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { + void getAccountStorageTrieNode_saveAndGetRegularValue(final FlatDbMode flatDbMode) { setUp(flatDbMode); - final Hash accountHash = Hash.hash(Address.fromHexString("0x1")); + final Hash accountHash = Address.fromHexString("0x1").addressHash(); final Bytes location = Bytes.fromHexString("0x01"); final Bytes bytes = Bytes.fromHexString("0x123456"); @@ -197,7 +197,7 @@ public void getAccountStorageTrieNode_saveAndGetRegularValue(final FlatDbMode fl @ParameterizedTest @MethodSource("data") - public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode(final FlatDbMode flatDbMode) { + void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode(final FlatDbMode flatDbMode) { setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.FULL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); @@ -229,7 +229,7 @@ public void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode(final FlatDbMod @ParameterizedTest @MethodSource("data") - public void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode(final FlatDbMode flatDbMode) { + void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode(final FlatDbMode flatDbMode) { setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); @@ -258,7 +258,7 @@ public void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode(final FlatDbMod @ParameterizedTest @MethodSource("data") - public void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flatDbMode) { + void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flatDbMode) { setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); @@ -290,7 +290,7 @@ public void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flat @ParameterizedTest @MethodSource("data") - public void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode flatDbMode) { + void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode flatDbMode) { setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); @@ -339,7 +339,7 @@ public void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode fla @ParameterizedTest @MethodSource("data") - public void getStorage_loadFromTrieWhenEmptyWithFullMode(final FlatDbMode flatDbMode) { + void getStorage_loadFromTrieWhenEmptyWithFullMode(final FlatDbMode flatDbMode) { setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.FULL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); @@ -359,7 +359,7 @@ public void getStorage_loadFromTrieWhenEmptyWithFullMode(final FlatDbMode flatDb @ParameterizedTest @MethodSource("data") - public void clear_reloadFlatDbStrategy(final FlatDbMode flatDbMode) { + void clear_reloadFlatDbStrategy(final FlatDbMode flatDbMode) { setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); @@ -379,11 +379,11 @@ public void clear_reloadFlatDbStrategy(final FlatDbMode flatDbMode) { @ParameterizedTest @MethodSource("data") - public void reconcilesNonConflictingUpdaters(final FlatDbMode flatDbMode) { + void reconcilesNonConflictingUpdaters(final FlatDbMode flatDbMode) { setUp(flatDbMode); - final Hash accountHashA = Hash.hash(Address.fromHexString("0x1")); - final Hash accountHashB = Hash.hash(Address.fromHexString("0x2")); - final Hash accountHashD = Hash.hash(Address.fromHexString("0x4")); + 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"); @@ -405,14 +405,14 @@ public void reconcilesNonConflictingUpdaters(final FlatDbMode flatDbMode) { @ParameterizedTest @MethodSource("data") - public void isWorldStateAvailable_defaultIsFalse(final FlatDbMode flatDbMode) { + void isWorldStateAvailable_defaultIsFalse(final FlatDbMode flatDbMode) { setUp(flatDbMode); assertThat(emptyStorage().isWorldStateAvailable(UInt256.valueOf(1), Hash.EMPTY)).isFalse(); } @ParameterizedTest @MethodSource("data") - public void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flatDbMode) { + void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flatDbMode) { setUp(flatDbMode); final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); @@ -427,7 +427,7 @@ public void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flat @ParameterizedTest @MethodSource("data") - public void isWorldStateAvailable_afterCallingSaveWorldstate(final FlatDbMode flatDbMode) { + 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 cbb125647bf..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 @@ -43,7 +43,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class CachedMerkleTrieLoaderTest { +class CachedMerkleTrieLoaderTest { private CachedMerkleTrieLoader merkleTrieLoader; private final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); @@ -59,12 +59,13 @@ public class CachedMerkleTrieLoaderTest { 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/proof/WorldStateProofProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java index 08f83d146bb..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 @@ -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/vm/DebugOperationTracerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java index d4b22c72622..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 @@ -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 5a6096047b4..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 @@ -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/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/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 cfe5f2697fc..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 @@ -56,7 +56,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class StorageFlatDatabaseHealingRangeRequestTest { +class StorageFlatDatabaseHealingRangeRequestTest { @Mock private SnapWorldDownloadState downloadState; @Mock private SnapSyncProcessState snapSyncState; @@ -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/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index a73ccd49c6c..269f4c2b7d2 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 @@ -53,7 +53,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; @@ -367,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) @@ -384,13 +381,13 @@ public void run() { .apparentValue(ethValue) .code(code) .blockValues(blockHeader) - .depth(0) .completer(c -> {}) .miningBeneficiary(blockHeader.getCoinbase()) .blockHashLookup(new CachingBlockHashLookup(blockHeader, component.getBlockchain())) - .build()); + .build(); final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompileContractRegistry); + final Deque messageFrameStack = initialMessageFrame.getMessageFrameStack(); stopwatch.start(); while (!messageFrameStack.isEmpty()) { final MessageFrame messageFrame = messageFrameStack.peek(); @@ -448,7 +445,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/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index 22a3ab80ade..33aad83a22d 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 @@ -81,6 +81,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 @@ -169,6 +184,15 @@ private void traceTestSpecs(final String test, final ListTo 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/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 1c7adf20850..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,6 +17,8 @@ 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; @@ -32,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; @@ -42,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; @@ -56,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 @@ -200,59 +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 Set
    creates; - 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. * @@ -264,87 +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.creates = 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(); } /** @@ -393,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; @@ -407,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); @@ -432,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; @@ -599,7 +555,7 @@ public int stackSize() { * @return The current return stack size */ public int returnStackSize() { - return returnStack.size(); + return returnStack.get().size(); } /** @@ -608,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(); } /** @@ -617,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); } /** @@ -948,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); } /** @@ -957,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); } /** @@ -971,7 +922,7 @@ public void clearSelfDestructs() { * @return the self-destruct set */ public Set
    getSelfDestructs() { - return selfDestructs; + return txValues.selfDestructs(); } /** @@ -980,7 +931,7 @@ public Set
    getSelfDestructs() { * @param address The recipient to create */ public void addCreate(final Address address) { - creates.add(address); + txValues.creates().add(address); } /** * Add addresses to the create set if they are not already present. @@ -988,12 +939,7 @@ public void addCreate(final Address address) { * @param addresses The addresses to create */ public void addCreates(final Set
    addresses) { - creates.addAll(addresses); - } - - /** Removes all entries in the create set. */ - public void clearCreates() { - creates.clear(); + txValues.creates().addAll(addresses); } /** @@ -1002,7 +948,7 @@ public void clearCreates() { * @return the create set */ public Set
    getCreates() { - return creates; + return txValues.creates(); } /** @@ -1015,8 +961,7 @@ public Set
    getCreates() { * transaction. */ public boolean wasCreatedInTransaction(final Address address) { - return creates.contains((address)) - || (parentMessageFrame != null && parentMessageFrame.wasCreatedInTransaction(address)); + return txValues.creates().contains((address)); } /** @@ -1045,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); } /** @@ -1071,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; } /** @@ -1167,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(); } /** @@ -1199,7 +1108,7 @@ public Address getContractAddress() { * @return the current gas price */ public Wei getGasPrice() { - return gasPrice; + return txValues.gasPrice(); } /** @@ -1235,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. */ @@ -1249,7 +1158,7 @@ public void notifyCompletion() { * @return the current message frame stack */ public Deque getMessageFrameStack() { - return messageFrameStack; + return txValues.messageFrameStack(); } /** @@ -1277,7 +1186,7 @@ public Optional getExceptionalHaltReason() { * @return the current mining beneficiary */ public Address getMiningBeneficiary() { - return miningBeneficiary; + return txValues.miningBeneficiary(); } /** @@ -1286,7 +1195,7 @@ public Address getMiningBeneficiary() { * @return the block hash lookup */ public Function getBlockHashLookup() { - return blockHashLookup; + return txValues.blockHashLookup(); } /** @@ -1304,7 +1213,7 @@ public Operation getCurrentOperation() { * @return the max stack size */ public int getMaxStackSize() { - return maxStackSize; + return txValues.maxStackSize(); } /** @@ -1356,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(); } /** @@ -1386,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; } /** @@ -1412,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); } /** @@ -1428,7 +1322,7 @@ public void commitTransientStorage() { * @return optional list of hashes */ public Optional> getVersionedHashes() { - return versionedHashes; + return txValues.versionedHashes(); } /** Reset. */ @@ -1440,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; @@ -1454,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; @@ -1468,24 +1361,25 @@ public static class Builder { 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; } @@ -1621,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. * @@ -1743,25 +1626,24 @@ public Builder versionedHashes(final Optional> versionedHash } 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"); - checkState(versionedHashes != null, "Missing optional versioned hashes"); } /** @@ -1772,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/operation/AbstractCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java index 12618e7ee41..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,33 +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()) - .versionedHashes(frame.getVersionedHashes()) - .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 { @@ -268,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 9b364347100..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 @@ -90,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 { @@ -147,31 +147,21 @@ private void spawnChildMessage(final MessageFrame parent, final Code code, final gasCalculator().gasAvailableForChildCreate(parent.getRemainingGas()); parent.decrementRemainingGas(childGasStipend); - final MessageFrame childFrame = - MessageFrame.builder() - .type(MessageFrame.Type.CONTRACT_CREATION) - .messageFrameStack(parent.getMessageFrameStack()) - .worldUpdater(parent.getWorldUpdater().updater()) - .initialGas(childGasStipend) - .address(contractAddress) - .originator(parent.getOriginatorAddress()) - .contract(contractAddress) - .gasPrice(parent.getGasPrice()) - .inputData(Bytes.EMPTY) - .sender(parent.getRecipientAddress()) - .value(value) - .apparentValue(value) - .code(code) - .blockValues(parent.getBlockValues()) - .depth(parent.getMessageStackDepth() + 1) - .completer(child -> complete(parent, child, evm)) - .miningBeneficiary(parent.getMiningBeneficiary()) - .blockHashLookup(parent.getBlockHashLookup()) - .maxStackSize(parent.getMaxStackSize()) - .versionedHashes(parent.getVersionedHashes()) - .build(); - - parent.getMessageFrameStack().addFirst(childFrame); + // 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); } @@ -190,7 +180,6 @@ private void complete(final MessageFrame frame, final MessageFrame childFrame, f frame.incrementGasRefund(childFrame.getGasRefund()); if (childFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) { - frame.mergeWarmedUpFields(childFrame); Address createdAddress = childFrame.getContractAddress(); frame.pushStackItem(Words.fromAddress(createdAddress)); onSuccess(frame, createdAddress); 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/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/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/operation/AbstractCreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java index cccd5194878..aa3dfd40217 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java @@ -41,7 +41,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 java.util.Optional; @@ -143,7 +143,6 @@ protected void onInvalid(final MessageFrame frame, final CodeInvalid invalidCode private void executeOperation(final Bytes contract, final EVM evm) { final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); - final ArrayDeque messageFrameStack = new ArrayDeque<>(); final MessageFrame messageFrame = MessageFrame.builder() .type(MessageFrame.Type.CONTRACT_CREATION) @@ -153,18 +152,17 @@ private void executeOperation(final Bytes contract, final EVM evm) { .value(Wei.ZERO) .apparentValue(Wei.ZERO) .code(CodeFactory.createCode(SIMPLE_CREATE, 0, true)) - .depth(1) .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) .worldUpdater(worldUpdater) .build(); + final Deque messageFrameStack = messageFrame.getMessageFrameStack(); messageFrame.pushStackItem(Bytes.ofUnsignedLong(contract.size())); messageFrame.pushStackItem(memoryOffset); messageFrame.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 index 3ed4d38a339..f596bed8aad 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java @@ -35,8 +35,6 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount; -import java.util.ArrayDeque; - import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -85,13 +83,11 @@ void checkContractDeletionCommon( .value(Wei.ZERO) .apparentValue(Wei.ZERO) .code(CodeFactory.createCode(SELFDESTRUCT_CODE, 0, true)) - .depth(1) .completer(__ -> {}) .address(originatorAddress) .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) 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 94230483ca5..5a4c57695e8 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 @@ -36,7 +36,6 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.math.BigInteger; -import java.util.ArrayDeque; import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -66,13 +65,11 @@ 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)) .gasPrice(Wei.ZERO) - .messageFrameStack(new ArrayDeque<>()) .miningBeneficiary(Address.ZERO) .originator(Address.ZERO) .initialGas(100_000L) 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; From ae335a1bc59e83019b1fab51e6ba7cf013c4ffad Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 9 Aug 2023 10:51:56 -0600 Subject: [PATCH 40/51] EVMTool contract create processing (#5755) The "code" mode of the EVMTool did not support the side effects of a contract create. Expose the TransactionProcessor method that handles that switching. Signed-off-by: Danno Ferrin --- CHANGELOG.md | 1 + .../mainnet/MainnetTransactionProcessor.java | 14 +++++--------- .../hyperledger/besu/evmtool/EvmToolCommand.java | 9 ++------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4986f1e594e..55c539ed2e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### 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) ### Download Links 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 a87a35d7257..64a8450cd38 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 @@ -506,21 +506,17 @@ public TransactionProcessingResult processTransaction( } } - 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/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index 269f4c2b7d2..0bd393b4fa9 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,8 +36,6 @@ 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; @@ -344,8 +342,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()) { @@ -385,13 +381,12 @@ public void run() { .miningBeneficiary(blockHeader.getCoinbase()) .blockHashLookup(new CachingBlockHashLookup(blockHeader, component.getBlockchain())) .build(); + Deque messageFrameStack = initialMessageFrame.getMessageFrameStack(); - final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompileContractRegistry); - final Deque messageFrameStack = initialMessageFrame.getMessageFrameStack(); 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) { From 86aed203f7f8f92bb3ad128488a6c0ece841a13d Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 14 Aug 2023 03:14:54 +0200 Subject: [PATCH 41/51] Uniform the way fee market is used in ProtocolSpecBuilder (#5746) Signed-off-by: Fabio Di Fabio Co-authored-by: Sally MacFarlane --- .../mainnet/ClassicProtocolSpecs.java | 20 ++--- .../mainnet/MainnetProtocolSpecs.java | 89 ++++++++++--------- .../ethereum/mainnet/ProtocolSpecBuilder.java | 27 +++--- 3 files changed, 73 insertions(+), 63 deletions(-) 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 f217e73e7dd..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 @@ -21,7 +21,6 @@ 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; @@ -74,8 +73,8 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( contractSizeLimit, configStackSizeLimit, evmConfiguration) .isReplayProtectionSupported(true) .gasCalculator(TangerineWhistleGasCalculator::new) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .name("ClassicTangerineWhistle"); } @@ -128,8 +127,8 @@ public static ProtocolSpecBuilder defuseDifficultyBombDefinition( return gothamDefinition( chainId, contractSizeLimit, configStackSizeLimit, ecip1017EraRounds, evmConfiguration) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .name("DefuseDifficultyBomb"); } @@ -171,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"); } @@ -291,8 +291,8 @@ public static ProtocolSpecBuilder magnetoDefinition( ecip1017EraRounds, evmConfiguration) .gasCalculator(BerlinGasCalculator::new) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, 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 bbdfc385664..1299dc9d01d 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 @@ -20,7 +20,6 @@ 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; @@ -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,12 +121,13 @@ public static ProtocolSpecBuilder frontierDefinition( false, Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 0)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, false, Optional.empty())) .transactionProcessorBuilder( (gasCalculator, + feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> @@ -197,8 +197,8 @@ public static ProtocolSpecBuilder homesteadDefinition( true, Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 0)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, true, Optional.empty())) .difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD) @@ -275,11 +275,12 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 1, SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId)) .transactionProcessorBuilder( (gasCalculator, + feeMarket, transactionValidator, contractCreationProcessor, messageCallProcessor) -> @@ -291,7 +292,7 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( true, false, stackSizeLimit, - FeeMarket.legacy(), + feeMarket, CoinbaseFeePriceCalculator.frontier())) .name("SpuriousDragon"); } @@ -316,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, @@ -410,8 +411,8 @@ static ProtocolSpecBuilder berlinDefinition( return muirGlacierDefinition( chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, evmConfiguration) .gasCalculator(BerlinGasCalculator::new) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, @@ -447,15 +448,18 @@ static ProtocolSpecBuilder londonDefinition( configStackSizeLimit, enableRevertReason, evmConfiguration) + .feeMarket(londonFeeMarket) .gasCalculator(LondonGasCalculator::new) - .gasLimitCalculator( - new LondonTargetingGasLimitCalculator(londonForkBlockNumber, londonFeeMarket)) - .transactionValidatorBuilder( - (gasCalculator, gasLimitCalculator) -> + .gasLimitCalculatorBuilder( + feeMarket -> + new LondonTargetingGasLimitCalculator( + londonForkBlockNumber, (BaseFeeMarket) feeMarket)) + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, - londonFeeMarket, + feeMarket, true, chainId, Set.of( @@ -465,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) -> @@ -491,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"); } @@ -574,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, @@ -597,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) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, - londonFeeMarket, + feeMarket, true, chainId, Set.of( @@ -646,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, @@ -660,7 +659,10 @@ static ProtocolSpecBuilder cancunDefinition( // gas calculator for EIP-4844 data gas .gasCalculator(CancunGasCalculator::new) // gas limit with EIP-4844 max data gas per block - .gasLimitCalculator(cancunGasLimitCalculator) + .gasLimitCalculatorBuilder( + feeMarket -> + new CancunTargetingGasLimitCalculator( + londonForkBlockNumber, (BaseFeeMarket) feeMarket)) // EVM changes to support EOF EIPs (3670, 4200, 4750, 5450) .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -680,6 +682,7 @@ static ProtocolSpecBuilder cancunDefinition( // use Cancun fee market .transactionProcessorBuilder( (gasCalculator, + feeMarket, transactionValidator, contractCreationProcessor, messageCallProcessor) -> @@ -691,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) -> + .transactionValidatorFactoryBuilder( + (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( gasCalculator, gasLimitCalculator, - cancunFeeMarket, + feeMarket, true, chainId, Set.of( 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 697f1112d2b..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 - transactionValidatorFactoryBuilder; + private TransactionValidatorFactoryBuilder transactionValidatorFactoryBuilder; private Function blockHeaderValidatorBuilder; private Function ommerHeaderValidatorBuilder; private Function blockBodyValidatorBuilder; @@ -88,8 +87,9 @@ public ProtocolSpecBuilder gasCalculator(final Supplier gasCalcul return this; } - public ProtocolSpecBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { - this.gasLimitCalculator = gasLimitCalculator; + public ProtocolSpecBuilder gasLimitCalculatorBuilder( + final Function gasLimitCalculatorBuilder) { + this.gasLimitCalculatorBuilder = gasLimitCalculatorBuilder; return this; } @@ -125,9 +125,8 @@ public ProtocolSpecBuilder evmBuilder( return this; } - public ProtocolSpecBuilder transactionValidatorBuilder( - final BiFunction - transactionValidatorFactoryBuilder) { + public ProtocolSpecBuilder transactionValidatorFactoryBuilder( + final TransactionValidatorFactoryBuilder transactionValidatorFactoryBuilder) { this.transactionValidatorFactoryBuilder = transactionValidatorFactoryBuilder; return this; } @@ -279,7 +278,7 @@ public ProtocolSpecBuilder isReplayProtectionSupported( 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(transactionValidatorFactoryBuilder, "Missing transaction validator"); @@ -306,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 TransactionValidatorFactory transactionValidatorFactory = - transactionValidatorFactoryBuilder.apply(gasCalculator, gasLimitCalculator); + transactionValidatorFactoryBuilder.apply(gasCalculator, gasLimitCalculator, feeMarket); final AbstractMessageProcessor contractCreationProcessor = contractCreationProcessorBuilder.apply(gasCalculator, evm); final PrecompileContractRegistry precompileContractRegistry = @@ -320,6 +320,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { final MainnetTransactionProcessor transactionProcessor = transactionProcessorBuilder.apply( gasCalculator, + feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor); @@ -446,6 +447,7 @@ private BlockHeaderValidator createBlockHeaderValidator( public interface TransactionProcessorBuilder { MainnetTransactionProcessor apply( GasCalculator gasCalculator, + FeeMarket feeMarket, TransactionValidatorFactory transactionValidatorFactory, AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor messageCallProcessor); @@ -484,4 +486,9 @@ BlockValidator apply( public interface BlockImporterBuilder { BlockImporter apply(BlockValidator blockValidator); } + + public interface TransactionValidatorFactoryBuilder { + TransactionValidatorFactory apply( + GasCalculator gasCalculator, GasLimitCalculator gasLimitCalculator, FeeMarket feeMarket); + } } From 06cbd7c9f4b1fbdc3a6145c78ba016feece6e7e4 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Tue, 15 Aug 2023 11:18:46 -0400 Subject: [PATCH 42/51] Cancun genesis tests (#5760) * bug in block serializer when Optional 4844 fields not present * adds test coverage for genesis block from genesis config * returns bad req when blobgas fields missing * uses matchers to lookup forks by predicates * corrects hash being used, still need externally provided fixture to cover it * added data message to invalid withdrawals response * improve null checks for excess data gas --------- Signed-off-by: Justin Florentine Signed-off-by: Sally MacFarlane Co-authored-by: Sally MacFarlane --- ...newPayloadV2_invalid_null_withdrawals.json | 3 +- .../engine/AbstractEngineNewPayload.java | 12 +- .../response/JsonRpcErrorResponse.java | 9 + .../engine/AbstractEngineNewPayloadTest.java | 118 +- .../engine/EngineNewPayloadEIP6110Test.java | 19 +- .../engine/EngineNewPayloadV2Test.java | 9 +- .../engine/EngineNewPayloadV3Test.java | 18 +- .../blockcreation/AbstractBlockCreator.java | 4 +- .../besu/ethereum/core/BlockHeader.java | 14 +- .../ethereum/core/ProcessableBlockHeader.java | 12 +- .../besu/ethereum/core/Transaction.java | 2 +- .../besu/ethereum/chain/GenesisStateTest.java | 97 + .../besu/ethereum/chain/genesis_cancun.json | 4076 +++++++++++++++++ .../besu/ethereum/chain/genesis_shanghai.json | 4076 +++++++++++++++++ .../referencetests/ReferenceTestEnv.java | 2 +- 15 files changed, 8386 insertions(+), 85 deletions(-) create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_cancun.json create mode 100644 ethereum/core/src/test/resources/org/hyperledger/besu/ethereum/chain/genesis_shanghai.json 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/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 8215eae8be3..59fd54f7d99 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 @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; 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; @@ -123,12 +124,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .addArgument(() -> Json.encodePrettily(blockParam)) .log(); - /* - ValidationResult forkValidationResult = validateForkSupported(reqId, blockParam); + ValidationResult forkValidationResult = validateForkSupported(reqId, blockParam); if (!forkValidationResult.isValid()) { - return new JsonRpcErrorResponse(reqId, forkValidationResult.getInvalidReason()); + return new JsonRpcErrorResponse(reqId, forkValidationResult); } - */ final Optional> maybeWithdrawals = Optional.ofNullable(blockParam.getWithdrawals()) @@ -137,7 +136,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 = @@ -146,7 +146,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()) { 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 8fd311685da..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,6 +14,8 @@ */ 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; @@ -51,6 +53,13 @@ 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") public Object getId() { return id; 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 aaaef981fcc..130aaad14b8 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 @@ -20,6 +20,7 @@ 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.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; @@ -59,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; @@ -70,12 +73,14 @@ 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.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.jupiter.MockitoExtension; @@ -83,11 +88,16 @@ @ExtendWith(MockitoExtension.class) public abstract class AbstractEngineNewPayloadTest { - protected final long LONDON_TIMESTAMP = 0; - protected final long PARIS_TIMESTAMP = 10; - protected final long SHANGHAI_TIMESTAMP = 20; - protected final long CANCUN_TIMESTAMP = 30; - protected final long EXPERIMENTAL_TIMESTAMP = 40; + 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 { @@ -100,6 +110,24 @@ AbstractEngineNewPayload create( final EngineCallListener engineCallListener); } + static class HardforkMatcher implements ArgumentMatcher> { + private final ScheduledProtocolSpec.Hardfork fork; + private final ScheduledProtocolSpec spec; + + 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; @@ -109,7 +137,7 @@ public AbstractEngineNewPayloadTest() {} protected static final Hash mockHash = Hash.hash(Bytes32.fromHexStringLenient("0x1337deadbeef")); @Mock protected ProtocolSpec protocolSpec; - @Mock protected ProtocolSchedule protocolSchedule; + @Mock protected DefaultProtocolSchedule protocolSchedule; @Mock protected ProtocolContext protocolContext; @Mock protected MergeContext mergeContext; @@ -134,6 +162,12 @@ public void before() { .thenReturn(new DepositsValidator.ProhibitedDeposits()); 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 @@ -146,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); @@ -157,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); @@ -192,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())); @@ -228,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); @@ -245,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(); @@ -278,21 +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")); @@ -306,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)); @@ -319,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())); @@ -356,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())); @@ -370,7 +397,7 @@ public void shouldRespondWithSyncingDuringBackwardsSync() { @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); @@ -387,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()); @@ -405,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); @@ -469,8 +499,8 @@ protected BlockHeader setupValidPayload( 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()) { 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 index aec754b484e..6088da3df3c 100644 --- 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 @@ -20,6 +20,7 @@ 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; @@ -37,7 +38,6 @@ 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.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import java.util.Collections; @@ -70,8 +70,7 @@ public void before() { engineCallListener); lenient() .when(protocolSchedule.hardforkFor(any())) - .thenReturn( - Optional.of(new ScheduledProtocolSpec.Hardfork("Cancun", super.CANCUN_TIMESTAMP))); + .thenReturn(Optional.of(super.cancunHardfork)); lenient().when(protocolSpec.getGasCalculator()).thenReturn(new CancunGasCalculator()); } @@ -85,11 +84,17 @@ 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)); @@ -126,7 +131,11 @@ public void shouldReturnValidIfDepositsIsNotNull_WhenDepositsAllowed() { 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); @@ -159,7 +168,7 @@ protected BlockHeader createBlockHeader( BlockHeader parentBlockHeader = new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) - .timestamp(super.EXPERIMENTAL_TIMESTAMP) + .timestamp(super.experimentalHardfork.milestone()) .excessDataGas(DataGas.ZERO) .dataGasUsed(100L) .buildHeader(); 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 314e3a17cea..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 @@ -19,6 +19,7 @@ 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; @@ -80,7 +81,9 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { 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); @@ -96,7 +99,9 @@ public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { 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); 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 index 17f34a03480..e98be62b2c2 100644 --- 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 @@ -16,10 +16,11 @@ 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.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; @@ -32,7 +33,6 @@ 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.ScheduledProtocolSpec; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import java.util.List; @@ -68,10 +68,6 @@ public void before() { ethPeers, engineCallListener); lenient().when(protocolSpec.getGasCalculator()).thenReturn(new CancunGasCalculator()); - lenient() - .when(protocolSchedule.hardforkFor(any())) - .thenReturn( - Optional.of(new ScheduledProtocolSpec.Hardfork("Cancun", super.CANCUN_TIMESTAMP))); } @Test @@ -97,16 +93,22 @@ protected BlockHeader createBlockHeader( BlockHeader parentBlockHeader = new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) - .timestamp(super.CANCUN_TIMESTAMP) + .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() + 1) + .timestamp(parentBlockHeader.getTimestamp() + 12) .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) + .excessDataGas(DataGas.ZERO) + .dataGasUsed(0L) .buildHeader(); return mockHeader; } 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 ceb6061b717..aba3110d099 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 @@ -303,12 +303,12 @@ private GasUsage computeExcessDataGas( .sum(); // casting parent excess data gas to long since for the moment it should be well below that // limit - DataGas ecessDataGas = + DataGas excessDataGas = DataGas.of( gasCalculator.computeExcessDataGas( parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), newBlobsCount)); DataGas used = DataGas.of(gasCalculator.dataGasCost(newBlobsCount)); - return new GasUsage(ecessDataGas, used); + return new GasUsage(excessDataGas, used); } return null; } 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 eb2e906af70..86bfabe4aee 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 @@ -216,9 +216,9 @@ public void writeTo(final RLPOutput out) { if (withdrawalsRoot != null) { out.writeBytes(withdrawalsRoot); } - if (excessDataGas != null && dataGasUsed != null) { - out.writeLongScalar(dataGasUsed); - out.writeUInt64Scalar(excessDataGas); + if (excessDataGas.isPresent() && dataGasUsed.isPresent()) { + out.writeLongScalar(dataGasUsed.get()); + out.writeUInt64Scalar(excessDataGas.get()); } if (depositsRoot != null) { out.writeBytes(depositsRoot); @@ -320,12 +320,8 @@ public String toString() { if (withdrawalsRoot != null) { sb.append("withdrawalsRoot=").append(withdrawalsRoot).append(", "); } - if (dataGasUsed != null) { - sb.append("dataGasUsed=").append(dataGasUsed).append(", "); - } - if (excessDataGas != null) { - sb.append("excessDataGas=").append(excessDataGas).append(", "); - } + dataGasUsed.ifPresent(aLong -> sb.append("dataGasUsed=").append(aLong).append(", ")); + excessDataGas.ifPresent(dataGas -> sb.append("excessDataGas=").append(dataGas).append(", ")); if (depositsRoot != null) { sb.append("depositsRoot=").append(depositsRoot); } 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 716782c047c..fd2318a85d2 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 @@ -45,9 +45,9 @@ public class ProcessableBlockHeader implements BlockValues { // prevRandao is included for post-merge blocks protected final Bytes32 mixHashOrPrevRandao; // dataGasUsed is included for Cancun - protected final Long dataGasUsed; + protected final Optional dataGasUsed; // excessDataGas is included for Cancun - protected final DataGas excessDataGas; + protected final Optional excessDataGas; protected ProcessableBlockHeader( final Hash parentHash, @@ -68,8 +68,8 @@ protected ProcessableBlockHeader( this.timestamp = timestamp; this.baseFee = baseFee; this.mixHashOrPrevRandao = mixHashOrPrevRandao; - this.dataGasUsed = dataGasUsed; - this.excessDataGas = excessDataGas; + this.dataGasUsed = Optional.ofNullable(dataGasUsed); + this.excessDataGas = Optional.ofNullable(excessDataGas); } /** @@ -169,11 +169,11 @@ public Optional getPrevRandao() { } public Optional getExcessDataGas() { - return Optional.ofNullable(excessDataGas); + return excessDataGas; } public Optional getDataGasUsed() { - return Optional.ofNullable(dataGasUsed); + return dataGasUsed; } public String toLogString() { 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 84228559606..798544c63ca 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 @@ -1323,7 +1323,7 @@ public Builder kzgBlobs( if (this.versionedHashes == null || this.versionedHashes.isEmpty()) { this.versionedHashes = kzgCommitments.stream() - .map(c -> new VersionedHash(SHA256_VERSION_ID, Sha256Hash.hash(c.getData()))) + .map(c -> new VersionedHash(SHA256_VERSION_ID, Sha256Hash.sha256(c.getData()))) .collect(Collectors.toList()); } this.blobsWithCommitments = 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 63e71ece52a..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; @@ -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/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/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 53aba098c1c..cfa73ac82a7 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 @@ -211,7 +211,7 @@ public BlockHeader updateFromParentValues(final ProtocolSpec protocolSpec) { .buildBlockHeader(), null))); } - if (excessDataGas == null && parentExcessBlobGas != null && parentBlobGasUsed != null) { + if (excessDataGas.isEmpty() && parentExcessBlobGas != null && parentBlobGasUsed != null) { builder.excessDataGas( DataGas.of( protocolSpec From 94f5e732398fd37e7c360e7ad5fc30ba6f802e4b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 15 Aug 2023 17:58:55 -0600 Subject: [PATCH 43/51] Update native libraries (#5749) Use the 0.8.1 version of native libraries, which uses better names for automatic modules for JPMS. Signed-off-by: Danno Ferrin --- CHANGELOG.md | 1 + gradle/verification-metadata.xml | 132 +++++++++++++++++++++++++++++++ gradle/versions.gradle | 2 +- 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55c539ed2e9..d4388afc22f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - 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) ### Download Links diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5150a2d83c1..06b602e29c3 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4625,6 +4625,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -4636,6 +4658,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -4647,6 +4691,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -4658,6 +4724,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -4669,6 +4757,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -4680,6 +4790,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index c69910057c2..54c62d8f251 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -160,7 +160,7 @@ dependencyManagement { dependency 'org.openjdk.jol:jol-core:0.17' 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' From 7019131d7b7cd066a46f8cb1620d3d3b761f2021 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 16 Aug 2023 12:06:08 -0500 Subject: [PATCH 44/51] Benchmarking in evmtool (#5754) Add a benchmarking command to EvmTool to benchmark performance of selected benchmarks. Signed-off-by: Danno Ferrin --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 2 +- .../hyperledger/besu/crypto/SECP256K1.java | 20 +- .../besu/evmtool/BenchmarkSubCommand.java | 95 ++++ .../besu/evmtool/EvmToolCommand.java | 4 + .../evmtool/benchmarks/AltBN128Benchmark.java | 183 +++++++ .../evmtool/benchmarks/BenchmarkExecutor.java | 153 ++++++ .../benchmarks/ECRecoverBenchmark.java | 466 ++++++++++++++++++ .../evmtool/benchmarks/ModExpBenchmark.java | 164 ++++++ .../benchmarks/Secp256k1Benchmark.java | 72 +++ .../hyperledger/besu/evm/EvmSpecVersion.java | 25 + .../AbstractAltBnPrecompiledContract.java | 12 +- ...ularExponentiationPrecompiledContract.java | 24 +- .../precompile/ECRECPrecompiledContract.java | 17 +- .../besu/evm/precompile/Benchmarks.java | 38 +- gradle/verification-metadata.xml | 66 --- 16 files changed, 1246 insertions(+), 96 deletions(-) create mode 100644 ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java create mode 100644 ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/AltBN128Benchmark.java create mode 100644 ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java create mode 100644 ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ECRecoverBenchmark.java create mode 100644 ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/ModExpBenchmark.java create mode 100644 ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/Secp256k1Benchmark.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d4388afc22f..13575e7c2b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - 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) ### Bug Fixes - Make smart contract permissioning features work with london fork [#5727](https://github.com/hyperledger/besu/pull/5727) 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 31c72c86411..c72a9766920 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1852,7 +1852,7 @@ private void configureNativeLibs() { } if (unstableNativeLibraryOptions.getNativeModExp() - && BigIntegerModularExponentiationPrecompiledContract.isNative()) { + && BigIntegerModularExponentiationPrecompiledContract.maybeEnableNative()) { logger.info("Using the native implementation of modexp"); } else { BigIntegerModularExponentiationPrecompiledContract.disableNative(); 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/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 0bd393b4fa9..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 @@ -85,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, @@ -227,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); 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/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/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..712b0fcc69d 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 @@ -44,15 +44,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 +66,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. * 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/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java b/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java index 5a4c57695e8..225212ddb8a 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,11 +28,11 @@ 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.math.BigInteger; import java.util.Map; @@ -45,6 +44,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +@SuppressWarnings("UnusedMethod") public class Benchmarks { static final Random random = new Random(); @@ -68,12 +68,12 @@ public class Benchmarks { .completer(__ -> {}) .address(Address.ZERO) .blockHashLookup(n -> null) - .blockValues(mock(BlockValues.class)) + .blockValues(new SimpleBlockValues()) .gasPrice(Wei.ZERO) .miningBeneficiary(Address.ZERO) .originator(Address.ZERO) .initialGas(100_000L) - .worldUpdater(mock(WorldUpdater.class)) + .worldUpdater(new SimpleWorld()) .build(); private static void benchSecp256k1Recover() { @@ -109,7 +109,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]; @@ -117,7 +117,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(); @@ -165,7 +165,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]; @@ -173,7 +173,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(); @@ -207,6 +207,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,10 +282,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() { @@ -403,7 +417,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/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 06b602e29c3..cd2a9ded305 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4625,17 +4625,6 @@ - - - - - - - - - - - @@ -4658,17 +4647,6 @@ - - - - - - - - - - - @@ -4691,17 +4669,6 @@ - - - - - - - - - - - @@ -4724,17 +4691,6 @@ - - - - - - - - - - - @@ -4757,17 +4713,6 @@ - - - - - - - - - - - @@ -4790,17 +4735,6 @@ - - - - - - - - - - - From 18975c73a086da884c2b80d50ba100121b24d5fa Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 17 Aug 2023 10:00:27 +1000 Subject: [PATCH 45/51] fix: Move maintainers to emeritus (#5743) * moved to emeritus Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- MAINTAINERS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 5a766b4696abca108b357621acc08dfeb340d7c8 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 16 Aug 2023 22:21:01 -0500 Subject: [PATCH 46/51] EvmTool fixes (#5763) * EvmTool fixes A mixed collection of EVMTool fixes * Ensure ECDSA algo is pre-configured * used clamped math in an old gas calculator * use correct gas calculator in fluent APIs Signed-off-by: Danno Ferrin * spotless Signed-off-by: Danno Ferrin --------- Signed-off-by: Danno Ferrin --- .../besu/evmtool/B11rSubCommand.java | 7 +++++-- .../besu/evmtool/MainnetGenesisFileModule.java | 17 +++++++++++++++++ .../besu/evmtool/StateTestSubCommand.java | 3 +++ .../besu/evmtool/T8nServerSubCommand.java | 3 +++ .../hyperledger/besu/evmtool/T8nSubCommand.java | 5 ++++- .../org/hyperledger/besu/evm/MainnetEVMs.java | 3 ++- ...odularExponentiationPrecompiledContract.java | 5 +++-- 7 files changed, 37 insertions(+), 6 deletions(-) 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 edd274088b7..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,6 +19,7 @@ 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; @@ -154,6 +155,8 @@ 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(); @@ -212,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); } } @@ -224,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/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 33aad83a22d..f31afc52053 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,6 +20,7 @@ import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts; import static org.hyperledger.besu.evmtool.StateTestSubCommand.COMMAND_NAME; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -115,6 +116,8 @@ 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 = 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 73e20be247e..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 @@ -17,6 +17,7 @@ import static org.hyperledger.besu.evmtool.T8nExecutor.extractTransactions; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; @@ -65,6 +66,8 @@ 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( new HttpServerOptions() 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 efcb3b71043..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,6 +19,7 @@ import static org.hyperledger.besu.evmtool.T8nSubCommand.COMMAND_ALIAS; import static org.hyperledger.besu.evmtool.T8nSubCommand.COMMAND_NAME; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; @@ -169,6 +170,8 @@ 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(); @@ -321,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) { 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 6398f23a507..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; @@ -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); } /** 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 712b0fcc69d..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; @@ -154,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; } } From 210927ed082d338692501f029814e1840109ebe6 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Fri, 18 Aug 2023 00:18:30 +1000 Subject: [PATCH 47/51] fix: prioritize fork error over missing payload fields (#5765) additional rpc error code for unsupported fork fixes #5738 Signed-off-by: Sally MacFarlane --- .../engine/AbstractEngineNewPayload.java | 18 ++++++++++-------- .../methods/engine/EngineNewPayloadV3.java | 4 ++-- .../internal/response/RpcErrorType.java | 1 + .../methods/engine/EngineNewPayloadV3Test.java | 5 +++++ 4 files changed, 18 insertions(+), 10 deletions(-) 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 59fd54f7d99..3f574a47b82 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 @@ -105,11 +105,18 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) final EnginePayloadParameter blockParam = requestContext.getRequiredParameter(0, EnginePayloadParameter.class); - Optional> maybeVersionedHashParam = + final Optional> maybeVersionedHashParam = requestContext.getOptionalList(1, String.class); - Object reqId = requestContext.getRequest().getId(); - Optional> maybeVersionedHashes; + 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) { @@ -124,11 +131,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .addArgument(() -> Json.encodePrettily(blockParam)) .log(); - ValidationResult forkValidationResult = validateForkSupported(reqId, blockParam); - if (!forkValidationResult.isValid()) { - return new JsonRpcErrorResponse(reqId, forkValidationResult); - } - final Optional> maybeWithdrawals = Optional.ofNullable(blockParam.getWithdrawals()) .map(ws -> ws.stream().map(WithdrawalParameter::toWithdrawal).collect(toList())); 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 index 6454c22fdb6..1bbf81a86be 100644 --- 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 @@ -54,12 +54,12 @@ protected ValidationResult validateForkSupported( if (cancun.isPresent() && payloadParameter.getTimestamp() >= cancun.get().milestone()) { if (payloadParameter.getDataGasUsed() == null || payloadParameter.getExcessDataGas() == null) { - return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing data gas fields"); + return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing blob gas fields"); } else { return ValidationResult.valid(); } } else { - return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Fork not supported"); + return ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK, "Fork not supported"); } } } 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 index 78017deca09..2b7096ceb42 100644 --- 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 @@ -81,6 +81,7 @@ public enum RpcErrorType { 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"), 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 index e98be62b2c2..c4abbfee9d6 100644 --- 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 @@ -73,7 +73,12 @@ public void before() { @Test public void shouldInvalidPayloadOnShortVersionedHash() { Bytes shortHash = Bytes.fromHexString("0x" + "69".repeat(31)); + EnginePayloadParameter payload = mock(EnginePayloadParameter.class); + when(payload.getTimestamp()).thenReturn(30l); + when(payload.getExcessDataGas()).thenReturn("99"); + when(payload.getDataGasUsed()).thenReturn(9l); + JsonRpcResponse badParam = method.response( new JsonRpcRequestContext( From 9706bd73290d30bb4c7503ba53130572e641002a Mon Sep 17 00:00:00 2001 From: matkt Date: Fri, 18 Aug 2023 10:28:49 +0200 Subject: [PATCH 48/51] Update worldstate state change behavior in case of FCU (#5699) Update the worldstate in the same way as the blockchain in order to avoid having inconsistencies between the two and later trigger a big rollforward Signed-off-by: Karim TAAM Co-authored-by: Ameziane H --- .../merge/blockcreation/MergeCoordinator.java | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) 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 47d6970007a..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 @@ -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() From 3b04f5cd27292237e934f9344d556fb8c507373b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Fri, 18 Aug 2023 17:39:33 -0500 Subject: [PATCH 49/51] Migrate DataGas to BlobGas (#5759) In all places move from DataGas to BlobGas when talking about 4844 gas. Signed-off-by: Danno Ferrin --- .../jsonrpc/engine/cancun/genesis.json | 4 +- .../test-cases/03_shanghai_newPayloadV2.json | 4 +- .../test-cases/04_shanghai_newPayloadV3.json | 4 +- .../test-cases/07_cancun_getPayloadV3.json | 4 +- .../test-cases/08_cancun_newPayloadV3.json | 4 +- .../besu/services/TraceServiceImpl.java | 14 ++-- .../besu/config/GenesisConfigFile.java | 16 ++-- .../datatypes/{DataGas.java => BlobGas.java} | 80 +++++++++--------- .../besu/datatypes/Transaction.java | 6 +- .../api/jsonrpc/JsonRpcResponseUtils.java | 4 +- .../api/jsonrpc/JsonRpcErrorConverter.java | 4 +- .../methods/ExecuteTransactionStep.java | 14 ++-- .../engine/AbstractEngineNewPayload.java | 40 ++++----- .../methods/engine/EngineNewPayloadV3.java | 4 +- .../parameters/EnginePayloadParameter.java | 20 ++--- .../internal/processor/BlockReplay.java | 34 ++++---- .../internal/processor/BlockTracer.java | 4 +- .../internal/processor/TransactionTracer.java | 24 +++--- .../internal/response/RpcErrorType.java | 2 +- .../jsonrpc/internal/results/BlockResult.java | 20 ++--- .../results/EngineGetPayloadResultV3.java | 22 ++--- .../results/TransactionCompleteResult.java | 14 ++-- .../results/TransactionPendingResult.java | 14 ++-- .../results/TransactionReceiptResult.java | 24 +++--- .../ethereum/api/query/BlockchainQueries.java | 32 ++++---- .../query/TransactionReceiptWithMetadata.java | 28 +++---- .../methods/EthGetTransactionReceiptTest.java | 14 ++-- .../engine/AbstractEngineNewPayloadTest.java | 6 +- .../engine/EngineGetPayloadV3Test.java | 12 +-- .../engine/EngineNewPayloadEIP6110Test.java | 10 +-- .../engine/EngineNewPayloadV3Test.java | 10 +-- .../processor/TransactionTracerTest.java | 2 +- .../blockcreation/AbstractBlockCreator.java | 37 ++++----- .../BlockTransactionSelector.java | 46 +++++------ .../AbstractBlockCreatorTest.java | 16 ++-- .../AbstractBlockTransactionSelectorTest.java | 8 +- .../besu/ethereum/GasLimitCalculator.java | 6 +- .../besu/ethereum/chain/GenesisState.java | 18 ++-- .../besu/ethereum/core/BlockHeader.java | 42 +++++----- .../ethereum/core/BlockHeaderBuilder.java | 40 ++++----- .../ethereum/core/ProcessableBlockHeader.java | 26 +++--- .../ethereum/core/SealableBlockHeader.java | 10 +-- .../besu/ethereum/core/Transaction.java | 82 +++++++++---------- .../core/encoding/BlobTransactionDecoder.java | 2 +- .../core/encoding/BlobTransactionEncoder.java | 2 +- .../feemarket/TransactionPriceCalculator.java | 20 ++--- .../mainnet/AbstractBlockProcessor.java | 10 +-- .../CancunTargetingGasLimitCalculator.java | 6 +- .../mainnet/MainnetBlockHeaderValidator.java | 4 +- .../mainnet/MainnetProtocolSpecs.java | 6 +- .../mainnet/MainnetTransactionProcessor.java | 24 +++--- .../mainnet/MainnetTransactionValidator.java | 24 +++--- .../mainnet/feemarket/CancunFeeMarket.java | 20 ++--- ...ator.java => ExcessBlobGasCalculator.java} | 20 ++--- .../ethereum/mainnet/feemarket/FeeMarket.java | 4 +- ...onRule.java => BlobGasValidationRule.java} | 30 +++---- .../transaction/TransactionInvalidReason.java | 2 +- .../transaction/TransactionSimulator.java | 14 ++-- .../ethereum/core/BlockDataGenerator.java | 12 +-- .../ethereum/core/BlockHeaderTestFixture.java | 18 ++-- .../ethereum/core/NonBesuBlockHeader.java | 4 +- .../ethereum/core/TransactionTestFixture.java | 8 +- .../besu/ethereum/bonsai/LogRollingTests.java | 4 +- .../ethereum/core/TransactionBuilderTest.java | 2 +- .../MainnetTransactionValidatorTest.java | 6 +- .../feemarket/CancunFeeMarketTest.java | 24 +++--- .../feemarket/ZeroBaseFeeMarketTest.java | 4 +- ...st.java => BlobGasValidationRuleTest.java} | 40 ++++----- .../blob_transactions_test_vectors.json | 8 +- .../backwardsync/ChainForTestCreator.java | 4 +- .../besu/evmtool/StateTestSubCommand.java | 8 +- .../hyperledger/besu/evmtool/T8nExecutor.java | 12 +-- ethereum/referencetests/build.gradle | 3 +- .../BlockchainReferenceTestCaseSpec.java | 12 ++- .../referencetests/ReferenceTestEnv.java | 12 +-- .../StateTestVersionedTransaction.java | 10 +-- .../vm/GeneralStateReferenceTestTools.java | 17 ++-- .../gascalculator/CancunGasCalculator.java | 54 ++++++------ .../besu/evm/gascalculator/GasCalculator.java | 20 ++--- .../CancunGasCalculatorTest.java | 12 +-- .../besu/evm/precompile/Benchmarks.java | 4 + plugin-api/build.gradle | 2 +- .../besu/plugin/data/BlockHeader.java | 12 +-- 83 files changed, 668 insertions(+), 657 deletions(-) rename datatypes/src/main/java/org/hyperledger/besu/datatypes/{DataGas.java => BlobGas.java} (54%) rename ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/{ExcessDataGasCalculator.java => ExcessBlobGasCalculator.java} (68%) rename ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/{DataGasValidationRule.java => BlobGasValidationRule.java} (60%) rename ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/{DataGasValidationRuleTest.java => BlobGasValidationRuleTest.java} (62%) 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 index b23dab36078..017d9f0c851 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/genesis.json @@ -4073,6 +4073,6 @@ "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "baseFeePerGas": null, - "dataGasUsed": null, - "excessDataGas": 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/03_shanghai_newPayloadV2.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/cancun/test-cases/03_shanghai_newPayloadV2.json index 57ecc2c349c..b9496a2b286 100644 --- 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 @@ -20,8 +20,8 @@ "blockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", "transactions": [], "withdrawals": [], - "dataGasUsed": null, - "excessDataGas": null + "blobGasUsed": null, + "excessBlobGas": null } ] }, 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 index dd468532406..bc43c2e42a5 100644 --- 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 @@ -20,8 +20,8 @@ "blockHash": "0x50c02dc77082fe2060b600cba0e6ce5a491af6d5323b2a90a7bc6359dd18e97b", "transactions": [], "withdrawals": [], - "dataGasUsed": null, - "excessDataGas": null + "blobGasUsed": null, + "excessBlobGas": null }, null ] 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 index 47be6015333..921659ba549 100644 --- 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 @@ -22,11 +22,11 @@ "timestamp": "0x1236", "extraData": "0x", "baseFeePerGas": "0x2da282a8", - "excessDataGas": "0x0", + "excessBlobGas": "0x0", "transactions": [], "withdrawals": [], "blockNumber": "0x2", - "dataGasUsed": "0x0", + "blobGasUsed": "0x0", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "blockHash": "0xc33d43425366d661ef70df12faf8ccd66ed7d0c6718d16d14868ba49e6786927" }, 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 index b3ed245ba19..0e80c75aabf 100644 --- 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 @@ -20,8 +20,8 @@ "blockHash": "0xc33d43425366d661ef70df12faf8ccd66ed7d0c6718d16d14868ba49e6786927", "transactions": [], "withdrawals": [], - "dataGasUsed": "0x0", - "excessDataGas": "0x0" + "blobGasUsed": "0x0", + "excessBlobGas": "0x0" }, [] ] 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 4a5e6f513f2..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,9 +15,9 @@ package org.hyperledger.besu.services; import static com.google.common.base.Preconditions.checkArgument; -import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; +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; @@ -111,15 +111,15 @@ private void trace(final Block block, final BlockAwareOperationTracer tracer) { transaction -> { final Optional maybeParentHeader = blockchain.getBlockHeader(header.getParentHash()); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPricePerGas( + .blobGasPricePerGas( maybeParentHeader .map( parent -> - calculateExcessDataGasForParent(protocolSpec, parent)) - .orElse(DataGas.ZERO)); + calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); tracer.traceStartTransaction(transaction); @@ -133,7 +133,7 @@ private void trace(final Block block, final BlockAwareOperationTracer tracer) { tracer, new CachingBlockHashLookup(header, blockchain), false, - dataGasPrice); + blobGasPrice); long transactionGasUsed = transaction.getGasLimit() - result.getGasRemaining(); tracer.traceEndTransaction(result.getOutput(), transactionGasUsed, 0); 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 9b706ab1a38..ad4be0c9f21 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java @@ -248,21 +248,21 @@ public String getNonce() { } /** - * Gets excess data gas. + * Gets excess blob gas. * - * @return the excess data gas + * @return the excess blob gas */ - public String getExcessDataGas() { - return JsonUtil.getValueAsString(configRoot, "excessdatagas", "0x0"); + public String getExcessBlobGas() { + return JsonUtil.getValueAsString(configRoot, "excessblobgas", "0x0"); } /** - * Gets data gas used. + * Gets blob gas used. * - * @return the data gas used + * @return the blob gas used */ - public String getDataGasUsed() { - return JsonUtil.getValueAsString(configRoot, "datagasused", "0x0"); + public String getBlobGasUsed() { + return JsonUtil.getValueAsString(configRoot, "blobgasused", "0x0"); } /** diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java similarity index 54% rename from datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java rename to datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java index 197edc29cfd..134e9cb4145 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/DataGas.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java @@ -20,97 +20,97 @@ import org.apache.tuweni.units.bigints.BaseUInt64Value; import org.apache.tuweni.units.bigints.UInt64; -/** A particular quantity of DataGas */ -public final class DataGas extends BaseUInt64Value implements Quantity { +/** A particular quantity of BlobGas */ +public final class BlobGas extends BaseUInt64Value implements Quantity { /** The constant ZERO. */ - public static final DataGas ZERO = of(0); + public static final BlobGas ZERO = of(0); /** The constant ONE. */ - public static final DataGas ONE = of(1); + public static final BlobGas ONE = of(1); - /** The constant MAX_DATA_GAS. */ - public static final DataGas MAX_DATA_GAS = of(UInt64.MAX_VALUE); + /** The constant MAX_BLOB_GAS. */ + public static final BlobGas MAX_BLOB_GAS = of(UInt64.MAX_VALUE); /** - * Instantiates a new DataGas. + * Instantiates a new BlobGas. * * @param value the value */ - DataGas(final UInt64 value) { - super(value, DataGas::new); + BlobGas(final UInt64 value) { + super(value, BlobGas::new); } - private DataGas(final long v) { + private BlobGas(final long v) { this(UInt64.valueOf(v)); } - private DataGas(final BigInteger v) { + private BlobGas(final BigInteger v) { this(UInt64.valueOf(v)); } - private DataGas(final String hexString) { + private BlobGas(final String hexString) { this(UInt64.fromHexString(hexString)); } /** - * data gas of value. + * blob gas of value. * * @param value the value - * @return the data gas + * @return the blob gas */ - public static DataGas of(final long value) { - return new DataGas(value); + public static BlobGas of(final long value) { + return new BlobGas(value); } /** - * data gas of value. + * blob gas of value. * * @param value the value - * @return the data gas + * @return the blob gas */ - public static DataGas of(final BigInteger value) { - return new DataGas(value); + public static BlobGas of(final BigInteger value) { + return new BlobGas(value); } /** - * data gas of value. + * blob gas of value. * * @param value the value - * @return the data gas + * @return the blob gas */ - public static DataGas of(final UInt64 value) { - return new DataGas(value); + public static BlobGas of(final UInt64 value) { + return new BlobGas(value); } /** - * data gas of value. + * blob gas of value. * * @param value the value - * @return the data gas + * @return the blob gas */ - public static DataGas ofNumber(final Number value) { - return new DataGas((BigInteger) value); + public static BlobGas ofNumber(final Number value) { + return new BlobGas((BigInteger) value); } /** - * Wrap data gas. + * Wrap blob gas. * * @param value the value - * @return the data gas + * @return the blob gas */ - public static DataGas wrap(final Bytes value) { - return new DataGas(UInt64.fromBytes(value)); + public static BlobGas wrap(final Bytes value) { + return new BlobGas(UInt64.fromBytes(value)); } /** - * From hex string to data gas. + * From hex string to blob gas. * * @param str the str - * @return the data gas + * @return the blob gas */ - public static DataGas fromHexString(final String str) { - return new DataGas(str); + public static BlobGas fromHexString(final String str) { + return new BlobGas(str); } @Override @@ -134,12 +134,12 @@ public String toShortHexString() { } /** - * From quantity to data gas. + * From quantity to blob gas. * * @param quantity the quantity - * @return the data gas + * @return the blob gas */ - public static DataGas fromQuantity(final Quantity quantity) { - return DataGas.wrap((Bytes) quantity); + public static BlobGas fromQuantity(final Quantity quantity) { + return BlobGas.wrap((Bytes) quantity); } } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java index 40cd95ab3b8..99eef4715b4 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java @@ -73,12 +73,12 @@ default Optional getMaxFeePerGas() { } /** - * 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. */ - default Optional getMaxFeePerDataGas() { + default Optional getMaxFeePerBlobGas() { return Optional.empty(); } 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 9c0a7490240..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 @@ -127,8 +127,8 @@ public JsonRpcResponse response( mixHash, nonce, withdrawalsRoot, - null, // ToDo 4844: set with the value of data_gas_used field - 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); 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 516b6aa1c07..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 @@ -73,8 +73,8 @@ public static RpcErrorType convertTransactionInvalidReason( return RpcErrorType.NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER; case LOWER_NONCE_INVALID_TRANSACTION_EXISTS: return RpcErrorType.LOWER_NONCE_INVALID_TRANSACTION_EXISTS; - case TOTAL_DATA_GAS_TOO_HIGH: - return RpcErrorType.TOTAL_DATA_GAS_TOO_HIGH; + case TOTAL_BLOB_GAS_TOO_HIGH: + return RpcErrorType.TOTAL_BLOB_GAS_TOO_HIGH; case TX_POOL_DISABLED: return RpcErrorType.TX_POOL_DISABLED; default: 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 99b157c2205..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,9 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; +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.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -88,13 +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() - .dataPricePerGas( + .blobGasPricePerGas( maybeParentHeader - .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) - .orElse(DataGas.ZERO)); + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(header, blockchain); result = transactionProcessor.processTransaction( @@ -106,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/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index 3f574a47b82..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 @@ -25,7 +25,7 @@ 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.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; @@ -57,7 +57,7 @@ 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.ExcessDataGasCalculator; +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; @@ -200,10 +200,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) blockParam.getPrevRandao(), 0, maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null), - blockParam.getDataGasUsed() == null ? null : blockParam.getDataGasUsed(), - blockParam.getExcessDataGas() == null + blockParam.getBlobGasUsed() == null ? null : blockParam.getBlobGasUsed(), + blockParam.getExcessBlobGas() == null ? null - : DataGas.fromHexString(blockParam.getExcessDataGas()), + : BlobGas.fromHexString(blockParam.getExcessBlobGas()), maybeDeposits.map(BodyValidation::depositsRoot).orElse(null), headerFunctions); @@ -430,40 +430,40 @@ protected ValidationResult validateBlobs( "Versioned hashes from blob transactions do not match expected values"); } - // Validate excessDataGas + // Validate excessBlobGas if (maybeParentHeader.isPresent()) { - if (!validateExcessDataGas(header, maybeParentHeader.get(), protocolSpec)) { + if (!validateExcessBlobGas(header, maybeParentHeader.get(), protocolSpec)) { return ValidationResult.invalid( RpcErrorType.INVALID_PARAMS, - "Payload excessDataGas does not match calculated excessDataGas"); + "Payload excessBlobGas does not match calculated excessBlobGas"); } } - // Validate dataGasUsed - if (header.getDataGasUsed().isPresent() && maybeVersionedHashes.isPresent()) { - if (!validateDataGasUsed(header, maybeVersionedHashes.get(), protocolSpec)) { + // Validate blobGasUsed + if (header.getBlobGasUsed().isPresent() && maybeVersionedHashes.isPresent()) { + if (!validateBlobGasUsed(header, maybeVersionedHashes.get(), protocolSpec)) { return ValidationResult.invalid( RpcErrorType.INVALID_PARAMS, - "Payload DataGasUsed does not match calculated DataGasUsed"); + "Payload BlobGasUsed does not match calculated BlobGasUsed"); } } return ValidationResult.valid(); } - private boolean validateExcessDataGas( + private boolean validateExcessBlobGas( final BlockHeader header, final BlockHeader parentHeader, final ProtocolSpec protocolSpec) { - DataGas calculatedDataGas = - ExcessDataGasCalculator.calculateExcessDataGasForParent(protocolSpec, parentHeader); - return header.getExcessDataGas().orElse(DataGas.ZERO).equals(calculatedDataGas); + BlobGas calculatedBlobGas = + ExcessBlobGasCalculator.calculateExcessBlobGasForParent(protocolSpec, parentHeader); + return header.getExcessBlobGas().orElse(BlobGas.ZERO).equals(calculatedBlobGas); } - private boolean validateDataGasUsed( + private boolean validateBlobGasUsed( final BlockHeader header, final List maybeVersionedHashes, final ProtocolSpec protocolSpec) { - var calculatedDataGas = - protocolSpec.getGasCalculator().dataGasCost(maybeVersionedHashes.size()); - return header.getDataGasUsed().orElse(0L).equals(calculatedDataGas); + var calculatedBlobGas = + protocolSpec.getGasCalculator().blobGasCost(maybeVersionedHashes.size()); + return header.getBlobGasUsed().orElse(0L).equals(calculatedBlobGas); } private Optional> extractVersionedHashes( 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 index 1bbf81a86be..d83b1f578a2 100644 --- 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 @@ -52,8 +52,8 @@ protected ValidationResult validateForkSupported( var cancun = timestampSchedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun")); if (cancun.isPresent() && payloadParameter.getTimestamp() >= cancun.get().milestone()) { - if (payloadParameter.getDataGasUsed() == null - || payloadParameter.getExcessDataGas() == null) { + if (payloadParameter.getBlobGasUsed() == null + || payloadParameter.getExcessBlobGas() == null) { return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing blob gas fields"); } else { return ValidationResult.valid(); 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 a643c4d1dba..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,8 +47,8 @@ public class EnginePayloadParameter { private final LogsBloomFilter logsBloom; private final List transactions; private final List withdrawals; - private final Long dataGasUsed; - private final String excessDataGas; + private final Long blobGasUsed; + private final String excessBlobGas; private final List versionedHashes; private final List deposits; @@ -69,8 +69,8 @@ public EnginePayloadParameter( @JsonProperty("prevRandao") final String prevRandao, @JsonProperty("transactions") final List transactions, @JsonProperty("withdrawals") final List withdrawals, - @JsonProperty("dataGasUsed") final UnsignedLongParameter dataGasUsed, - @JsonProperty("excessDataGas") final String excessDataGas, + @JsonProperty("blobGasUsed") final UnsignedLongParameter blobGasUsed, + @JsonProperty("excessBlobGas") final String excessBlobGas, @JsonProperty("versionedHashes") final List versionedHashes, @JsonProperty("deposits") final List deposits) { this.blockHash = blockHash; @@ -88,8 +88,8 @@ public EnginePayloadParameter( this.prevRandao = Bytes32.fromHexString(prevRandao); this.transactions = transactions; this.withdrawals = withdrawals; - this.dataGasUsed = dataGasUsed == null ? null : dataGasUsed.getValue(); - this.excessDataGas = excessDataGas; + this.blobGasUsed = blobGasUsed == null ? null : blobGasUsed.getValue(); + this.excessBlobGas = excessBlobGas; this.versionedHashes = versionedHashes; this.deposits = deposits; } @@ -154,12 +154,12 @@ public List getWithdrawals() { return withdrawals; } - public Long getDataGasUsed() { - return dataGasUsed; + public Long getBlobGasUsed() { + return blobGasUsed; } - public String getExcessDataGas() { - return excessDataGas; + public String getExcessBlobGas() { + return excessBlobGas; } public List getDeposits() { 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 49fe92cf604..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,9 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor; -import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; +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.processor.Tracer.TraceableState; @@ -51,21 +51,21 @@ public Optional block( block.getHeader(), block.getBody(), (body, header, blockchain, transactionProcessor, protocolSpec) -> { - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPricePerGas( + .blobGasPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) - .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)); }); @@ -85,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() - .dataPricePerGas( + .blobGasPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) - .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, @@ -109,7 +109,7 @@ public Optional beforeTransactionInBlock( blockHashLookup, false, TransactionValidationParams.blockReplay(), - dataGasPrice); + blobGasPrice); } } return Optional.empty(); @@ -125,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, @@ -136,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); }); } @@ -199,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 141321a9b18..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,9 +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.ExcessDataGasCalculator.calculateExcessDataGasForParent; +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; @@ -74,7 +74,7 @@ public Optional traceTransaction( mutableWorldState, blockHash, transactionHash, - (transaction, header, blockchain, transactionProcessor, dataGasPrice) -> { + (transaction, header, blockchain, transactionProcessor, blobGasPrice) -> { final TransactionProcessingResult result = processTransaction( header, @@ -83,7 +83,7 @@ public Optional traceTransaction( transaction, transactionProcessor, tracer, - dataGasPrice); + blobGasPrice); return new TransactionTrace(transaction, result, tracer.getTraceFrames()); }); return transactionTrace; @@ -116,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() - .dataPricePerGas( + .blobGasPricePerGas( blockchain .getBlockHeader(header.getParentHash()) - .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) - .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); @@ -140,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)); @@ -157,7 +157,7 @@ public List traceTransactionToFile( transaction, transactionProcessor, OperationTracer.NO_TRACING, - dataGasPrice); + blobGasPrice); } } return Optional.of(traces); @@ -188,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, @@ -199,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/RpcErrorType.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java index 2b7096ceb42..c3ef46016d9 100644 --- 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 @@ -73,7 +73,7 @@ public enum RpcErrorType { -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"), + TOTAL_BLOB_GAS_TOO_HIGH(-32000, "Total blob gas too high"), // Execution engine failures UNKNOWN_PAYLOAD(-32001, "Payload does not exist / is not available"), 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 9cc1f4e2cd9..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,8 +84,8 @@ public class BlockResult implements JsonRpcResult { private final String withdrawalsRoot; private final List withdrawals; - private final String dataGasUsed; - private final String excessDataGas; + private final String blobGasUsed; + private final String excessBlobGas; public BlockResult( final BlockHeader header, @@ -132,8 +132,8 @@ public BlockResult( .map(w -> w.stream().map(WithdrawalParameter::fromWithdrawal).collect(toList())) .orElse(null); - this.dataGasUsed = header.getDataGasUsed().map(Quantity::create).orElse(null); - this.excessDataGas = header.getExcessDataGas().map(Quantity::create).orElse(null); + this.blobGasUsed = header.getBlobGasUsed().map(Quantity::create).orElse(null); + this.excessBlobGas = header.getExcessBlobGas().map(Quantity::create).orElse(null); } @JsonGetter(value = "number") @@ -257,13 +257,13 @@ public List getWithdrawals() { return withdrawals; } - @JsonGetter(value = "dataGasUsed") - public String getDataGasUsed() { - return dataGasUsed; + @JsonGetter(value = "blobGasUsed") + public String getBlobGasUsed() { + return blobGasUsed; } - @JsonGetter(value = "excessDataGas") - public String getExcessDataGas() { - return excessDataGas; + @JsonGetter(value = "excessBlobGas") + public String getExcessBlobGas() { + return excessBlobGas; } } 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 index f499e6da868..985ddc66359 100644 --- 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 @@ -75,9 +75,9 @@ public static class PayloadResult { private final String extraData; private final String baseFeePerGas; - private final String excessDataGas; + private final String excessBlobGas; - private final String dataGasUsed; + private final String blobGasUsed; protected final List transactions; private final List withdrawals; @@ -108,9 +108,9 @@ public PayloadResult( .map(WithdrawalParameter::fromWithdrawal) .collect(Collectors.toList())) .orElse(null); - this.dataGasUsed = header.getDataGasUsed().map(Quantity::create).orElse(Quantity.HEX_ZERO); - this.excessDataGas = - header.getExcessDataGas().map(Quantity::create).orElse(Quantity.HEX_ZERO); + 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") @@ -189,14 +189,14 @@ public String getFeeRecipient() { return feeRecipient; } - @JsonGetter(value = "excessDataGas") - public String getExcessDataGas() { - return excessDataGas; + @JsonGetter(value = "excessBlobGas") + public String getExcessBlobGas() { + return excessBlobGas; } - @JsonGetter(value = "dataGasUsed") - public String getDataGasUseds() { - return dataGasUsed; + @JsonGetter(value = "blobGasUsed") + public String getBlobGasUseds() { + return blobGasUsed; } } } 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 3cbc5c40309..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 @@ -38,7 +38,7 @@ "gasPrice", "maxPriorityFeePerGas", "maxFeePerGas", - "maxFeePerDataGas", + "maxFeePerBlobGas", "hash", "input", "nonce", @@ -73,7 +73,7 @@ public class TransactionCompleteResult 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; @@ -102,8 +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.maxFeePerDataGas = - transaction.getMaxFeePerDataGas().map(Wei::toShortHexString).orElse(null); + this.maxFeePerBlobGas = + transaction.getMaxFeePerBlobGas().map(Wei::toShortHexString).orElse(null); this.gasPrice = Quantity.create( transaction @@ -165,9 +165,9 @@ public String getMaxFeePerGas() { return maxFeePerGas; } - @JsonGetter(value = "maxFeePerDataGas") - public String getMaxFeePerDataGas() { - return maxFeePerDataGas; + @JsonGetter(value = "maxFeePerBlobGas") + public String getMaxFeePerBlobGas() { + return maxFeePerBlobGas; } @JsonGetter(value = "gasPrice") 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 1b98c88c946..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 @@ -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; @@ -92,8 +92,8 @@ 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(); @@ -147,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") 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 ea233098197..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 @@ -47,8 +47,8 @@ "transactionIndex", "revertReason", "type", - "dataGasUsed", - "dataGasPrice" + "blobGasUsed", + "blobGasPrice" }) public abstract class TransactionReceiptResult { @@ -69,8 +69,8 @@ public abstract class TransactionReceiptResult { protected final TransactionReceipt receipt; protected final String type; - private final String dataGasUsed; - private final String dataGasPrice; + private final String blobGasUsed; + private final String blobGasPrice; protected TransactionReceiptResult(final TransactionReceiptWithMetadata receiptWithMetadata) { final Transaction txn = receiptWithMetadata.getTransaction(); @@ -81,8 +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.dataGasUsed = receiptWithMetadata.getDataGasUsed().map(Quantity::create).orElse(null); - this.dataGasPrice = receiptWithMetadata.getDataGasPrice().map(Quantity::create).orElse(null); + 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())); @@ -134,16 +134,16 @@ public String getGasUsed() { return gasUsed; } - @JsonGetter(value = "dataGasUsed") + @JsonGetter(value = "blobGasUsed") @JsonInclude(JsonInclude.Include.NON_NULL) - public String getDataGasUsed() { - return dataGasUsed; + public String getBlobGasUsed() { + return blobGasUsed; } - @JsonGetter(value = "dataGasPrice") + @JsonGetter(value = "blobGasPrice") @JsonInclude(JsonInclude.Include.NON_NULL) - public String getDataGasPrice() { - return dataGasPrice; + public String getBlobGasPrice() { + return blobGasPrice; } @JsonGetter(value = "effectiveGasPrice") 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 4e8aea3fe73..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,7 +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.ExcessDataGasCalculator.calculateExcessDataGasForParent; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; @@ -642,11 +642,11 @@ public Optional transactionReceiptByTransactionH - transactionReceipts.get(location.getTransactionIndex() - 1).getCumulativeGasUsed(); } - Optional maybeDataGasUsed = - getDataGasUsed(transaction, protocolSchedule.getByBlockHeader(header)); + Optional maybeBlobGasUsed = + getBlobGasUsed(transaction, protocolSchedule.getByBlockHeader(header)); - Optional maybeDataGasPrice = - getDataGasPrice(transaction, header, protocolSchedule.getByBlockHeader(header)); + Optional maybeBlobGasPrice = + getBlobGasPrice(transaction, header, protocolSchedule.getByBlockHeader(header)); return Optional.of( TransactionReceiptWithMetadata.create( @@ -658,35 +658,35 @@ public Optional transactionReceiptByTransactionH header.getBaseFee(), blockhash, header.getNumber(), - maybeDataGasUsed, - maybeDataGasPrice)); + maybeBlobGasUsed, + maybeBlobGasPrice)); } /** - * Calculates the data gas used for data in a transaction. + * 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 data gas used for data if the transaction type supports + * @return an Optional containing the blob gas used for data if the transaction type supports * blobs, otherwise returns an empty Optional */ - private Optional getDataGasUsed( + private Optional getBlobGasUsed( final Transaction transaction, final ProtocolSpec protocolSpec) { return transaction.getType().supportsBlob() - ? Optional.of(protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount())) + ? Optional.of(protocolSpec.getGasCalculator().blobGasCost(transaction.getBlobCount())) : Optional.empty(); } /** - * Calculates the data gas price for data in a transaction. + * 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 data gas price for data if the transaction type supports + * @return an Optional containing the blob gas price for data if the transaction type supports * blobs, otherwise returns an empty Optional */ - private Optional getDataGasPrice( + private Optional getBlobGasPrice( final Transaction transaction, final BlockHeader header, final ProtocolSpec protocolSpec) { if (transaction.getType().supportsBlob()) { return blockchain @@ -695,8 +695,8 @@ private Optional getDataGasPrice( parentHeader -> protocolSpec .getFeeMarket() - .dataPricePerGas( - calculateExcessDataGasForParent(protocolSpec, parentHeader))); + .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 77a910cfc1b..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,8 +30,8 @@ public class TransactionReceiptWithMetadata { private final long blockNumber; private final Hash blockHash; private final Transaction transaction; - private final Optional dataGasUsed; - private final Optional dataGasPrice; + private final Optional blobGasUsed; + private final Optional blobGasPrice; private TransactionReceiptWithMetadata( final TransactionReceipt receipt, @@ -42,8 +42,8 @@ private TransactionReceiptWithMetadata( final Optional baseFee, final Hash blockHash, final long blockNumber, - final Optional dataGasUsed, - final Optional dataGasPrice) { + final Optional blobGasUsed, + final Optional blobGasPrice) { this.receipt = receipt; this.transactionHash = transactionHash; this.transactionIndex = transactionIndex; @@ -52,8 +52,8 @@ private TransactionReceiptWithMetadata( this.blockHash = blockHash; this.blockNumber = blockNumber; this.transaction = transaction; - this.dataGasUsed = dataGasUsed; - this.dataGasPrice = dataGasPrice; + this.blobGasUsed = blobGasUsed; + this.blobGasPrice = blobGasPrice; } public static TransactionReceiptWithMetadata create( @@ -65,8 +65,8 @@ public static TransactionReceiptWithMetadata create( final Optional baseFee, final Hash blockHash, final long blockNumber, - final Optional dataGasUsed, - final Optional dataGasPrice) { + final Optional blobGasUsed, + final Optional blobGasPrice) { return new TransactionReceiptWithMetadata( receipt, transaction, @@ -76,8 +76,8 @@ public static TransactionReceiptWithMetadata create( baseFee, blockHash, blockNumber, - dataGasUsed, - dataGasPrice); + blobGasUsed, + blobGasPrice); } public TransactionReceipt getReceipt() { @@ -114,11 +114,11 @@ public Optional getBaseFee() { return baseFee; } - public Optional getDataGasUsed() { - return dataGasUsed; + public Optional getBlobGasUsed() { + return blobGasUsed; } - public Optional getDataGasPrice() { - return dataGasPrice; + public Optional getBlobGasPrice() { + return blobGasPrice; } } 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 649b0cae084..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 @@ -23,7 +23,7 @@ import org.hyperledger.besu.crypto.SECPSignature; 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.TransactionType; import org.hyperledger.besu.datatypes.Wei; @@ -263,11 +263,11 @@ public void shouldWorkFor1559Txs() { } /** - * Test case to verify that the TransactionReceiptStatusResult contains data gas used and data gas + * 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 shouldContainDataGasUsedAndDataGasPriceWhenBlobTransaction() { + public void shouldContainBlobGasUsedAndBlobGasPriceWhenBlobTransaction() { var hash = Hash.wrap(Bytes32.random()); mockBlockWithBlobTransaction(hash, 1L); @@ -282,8 +282,8 @@ public void shouldContainDataGasUsedAndDataGasPriceWhenBlobTransaction() { (TransactionReceiptStatusResult) response.getResult(); assertThat(result.getType()).isEqualTo("0x3"); - assertThat(result.getDataGasUsed()).isEqualTo("0x20000"); - assertThat(result.getDataGasPrice()).isEqualTo("0x1"); + assertThat(result.getBlobGasUsed()).isEqualTo("0x20000"); + assertThat(result.getBlobGasPrice()).isEqualTo("0x1"); } private void mockBlockWithBlobTransaction(final Hash blockHash, final long blockNumber) { @@ -303,7 +303,7 @@ private void mockBlockWithBlobTransaction(final Hash blockHash, final long block when(block.getBody()).thenReturn(body); when(body.getTransactions()) .thenReturn(List.of(new BlockDataGenerator().transaction(TransactionType.BLOB))); - when(parentHeader.getExcessDataGas()).thenReturn(Optional.of(DataGas.of(1000))); + when(parentHeader.getExcessBlobGas()).thenReturn(Optional.of(BlobGas.of(1000))); when(blockchain.getBlockByHash(blockHash)).thenReturn(Optional.of(block)); mockProtocolSpec(header); when(blockchain.getTransactionLocation(receiptHash)) @@ -312,7 +312,7 @@ private void mockBlockWithBlobTransaction(final Hash blockHash, final long block private void mockProtocolSpec(final BlockHeader blockHeader) { FeeMarket feeMarket = mock(CancunFeeMarket.class); - when(feeMarket.dataPricePerGas(any())).thenCallRealMethod(); + when(feeMarket.blobGasPricePerGas(any())).thenCallRealMethod(); ProtocolSpec spec = mock(ProtocolSpec.class); when(spec.getFeeMarket()).thenReturn(feeMarket); when(spec.getGasCalculator()).thenReturn(new CancunGasCalculator()); 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 130aaad14b8..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 @@ -31,7 +31,7 @@ import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; @@ -486,8 +486,8 @@ protected EnginePayloadParameter mockPayload( header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), txs, withdrawals, - header.getDataGasUsed().map(UnsignedLongParameter::new).orElse(null), - header.getExcessDataGas().map(DataGas::toHexString).orElse(null), + header.getBlobGasUsed().map(UnsignedLongParameter::new).orElse(null), + header.getExcessBlobGas().map(BlobGas::toHexString).orElse(null), versionedHashes, deposits); } 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 index 6d2f432f726..d024ac9fe15 100644 --- 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 @@ -24,8 +24,8 @@ 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.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; @@ -100,7 +100,7 @@ public void shouldReturnBlockForKnownPayloadId() { new BlockHeaderTestFixture() .prevRandao(Bytes32.random()) .timestamp(CANCUN_AT + 1) - .excessDataGas(DataGas.of(10L)) + .excessBlobGas(BlobGas.of(10L)) .buildHeader(); // should return withdrawals and excessGas for a post-cancun block PayloadIdentifier postCancunPid = @@ -119,7 +119,7 @@ public void shouldReturnBlockForKnownPayloadId() { .type(TransactionType.BLOB) .chainId(Optional.of(BigInteger.ONE)) .maxFeePerGas(Optional.of(Wei.of(15))) - .maxFeePerDataGas(Optional.of(Wei.of(128))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) .maxPriorityFeePerGas(Optional.of(Wei.of(1))) .blobsWithCommitments(Optional.of(bwc)) .versionedHashes(Optional.of(bwc.getVersionedHashes())) @@ -153,10 +153,10 @@ public void shouldReturnBlockForKnownPayloadId() { assertThat(res.getBlockValue()).isEqualTo(Quantity.create(0)); assertThat(res.getExecutionPayload().getPrevRandao()) .isEqualTo(cancunHeader.getPrevRandao().map(Bytes32::toString).orElse("")); - // excessDataGas: QUANTITY, 256 bits + // excessBlobGas: QUANTITY, 256 bits String expectedQuantityOf10 = Bytes32.leftPad(Bytes.of(10)).toQuantityHexString(); - assertThat(res.getExecutionPayload().getExcessDataGas()).isNotEmpty(); - assertThat(res.getExecutionPayload().getExcessDataGas()) + assertThat(res.getExecutionPayload().getExcessBlobGas()).isNotEmpty(); + assertThat(res.getExecutionPayload().getExcessBlobGas()) .isEqualTo(expectedQuantityOf10); }); verify(engineCallListener, times(1)).executionEngineCalled(); 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 index 6088da3df3c..a00b868ff30 100644 --- 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 @@ -26,7 +26,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; @@ -169,8 +169,8 @@ protected BlockHeader createBlockHeader( new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) .timestamp(super.experimentalHardfork.milestone()) - .excessDataGas(DataGas.ZERO) - .dataGasUsed(100L) + .excessBlobGas(BlobGas.ZERO) + .blobGasUsed(100L) .buildHeader(); BlockHeader mockHeader = @@ -180,8 +180,8 @@ protected BlockHeader createBlockHeader( .number(parentBlockHeader.getNumber() + 1) .timestamp(parentBlockHeader.getTimestamp() + 1) .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) - .excessDataGas(DataGas.ZERO) - .dataGasUsed(100L) + .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/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java index c4abbfee9d6..2cb130b2bbd 100644 --- 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 @@ -20,7 +20,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.datatypes.DataGas; +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; @@ -76,8 +76,8 @@ public void shouldInvalidPayloadOnShortVersionedHash() { EnginePayloadParameter payload = mock(EnginePayloadParameter.class); when(payload.getTimestamp()).thenReturn(30l); - when(payload.getExcessDataGas()).thenReturn("99"); - when(payload.getDataGasUsed()).thenReturn(9l); + when(payload.getExcessBlobGas()).thenReturn("99"); + when(payload.getBlobGasUsed()).thenReturn(9l); JsonRpcResponse badParam = method.response( @@ -112,8 +112,8 @@ protected BlockHeader createBlockHeader( .timestamp(parentBlockHeader.getTimestamp() + 12) .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) - .excessDataGas(DataGas.ZERO) - .dataGasUsed(0L) + .excessBlobGas(BlobGas.ZERO) + .blobGasUsed(0L) .buildHeader(); return mockHeader; } 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 88266a64117..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 @@ -120,7 +120,7 @@ public void setUp() throws Exception { when(blockchain.getChainHeadHeader()).thenReturn(blockHeader); when(protocolSpec.getBadBlocksManager()).thenReturn(new BadBlockManager()); when(protocolSpec.getGasCalculator()).thenReturn(gasCalculator); - lenient().when(gasCalculator.computeExcessDataGas(anyLong(), anyInt())).thenReturn(0L); + lenient().when(gasCalculator.computeExcessBlobGas(anyLong(), anyInt())).thenReturn(0L); } @Test 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 aba3110d099..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,10 +14,10 @@ */ package org.hyperledger.besu.ethereum.blockcreation; -import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; +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; @@ -171,10 +171,10 @@ protected BlockCreationResult createBlock( createPendingBlockHeader(timestamp, maybePrevRandao, newProtocolSpec); final Address miningBeneficiary = miningBeneficiaryCalculator.getMiningBeneficiary(processableBlockHeader.getNumber()); - Wei dataGasPrice = + Wei blobGasPrice = newProtocolSpec .getFeeMarket() - .dataPricePerGas(calculateExcessDataGasForParent(newProtocolSpec, parentHeader)); + .blobGasPricePerGas(calculateExcessBlobGasForParent(newProtocolSpec, parentHeader)); throwIfStopped(); @@ -187,7 +187,7 @@ protected BlockCreationResult createBlock( disposableWorldState, maybeTransactions, miningBeneficiary, - dataGasPrice, + blobGasPrice, newProtocolSpec); transactionResults.logSelectionStats(); @@ -230,7 +230,7 @@ protected BlockCreationResult createBlock( throwIfStopped(); - final GasUsage usage = computeExcessDataGas(transactionResults, newProtocolSpec); + final GasUsage usage = computeExcessBlobGas(transactionResults, newProtocolSpec); throwIfStopped(); @@ -251,7 +251,7 @@ protected BlockCreationResult createBlock( : null) .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)); if (usage != null) { - builder.dataGasUsed(usage.used.toLong()).excessDataGas(usage.excessDataGas); + builder.blobGasUsed(usage.used.toLong()).excessBlobGas(usage.excessBlobGas); } final SealableBlockHeader sealableBlockHeader = builder.buildSealableBlockHeader(); @@ -288,10 +288,9 @@ List findDepositsFromReceipts(final TransactionSelectionResults transac .toList(); } - record GasUsage(DataGas excessDataGas, DataGas used) {} - ; + record GasUsage(BlobGas excessBlobGas, BlobGas used) {} - private GasUsage computeExcessDataGas( + private GasUsage computeExcessBlobGas( final TransactionSelectionResults transactionResults, final ProtocolSpec newProtocolSpec) { if (newProtocolSpec.getFeeMarket().implementsDataFee()) { @@ -301,14 +300,14 @@ private GasUsage 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 - DataGas excessDataGas = - DataGas.of( - gasCalculator.computeExcessDataGas( - parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), newBlobsCount)); - DataGas used = DataGas.of(gasCalculator.dataGasCost(newBlobsCount)); - return new GasUsage(excessDataGas, used); + 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; } @@ -318,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(); @@ -338,7 +337,7 @@ private TransactionSelectionResults selectTransactions( 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/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index efce946ed02..7420e54e70c 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -88,27 +88,27 @@ public static class TransactionSelectionResults { private final Map notSelectedTransactions = new HashMap<>(); private long cumulativeGasUsed = 0; - private long cumulativeDataGasUsed = 0; + private long cumulativeBlobGasUsed = 0; private void updateSelected( final Transaction transaction, final TransactionReceipt receipt, final long gasUsed, - final long dataGasUsed) { + 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(selectedTransactions::size) .addArgument(cumulativeGasUsed) - .addArgument(cumulativeDataGasUsed) + .addArgument(cumulativeBlobGasUsed) .log(); } @@ -133,8 +133,8 @@ public long getCumulativeGasUsed() { return cumulativeGasUsed; } - public long getCumulativeDataGasUsed() { - return cumulativeDataGasUsed; + public long getCumulativeBlobGasUsed() { + return cumulativeBlobGasUsed; } public Map getNotSelectedTransactions() { @@ -174,7 +174,7 @@ public boolean equals(final Object o) { } TransactionSelectionResults that = (TransactionSelectionResults) o; return cumulativeGasUsed == that.cumulativeGasUsed - && cumulativeDataGasUsed == that.cumulativeDataGasUsed + && cumulativeBlobGasUsed == that.cumulativeBlobGasUsed && selectedTransactions.equals(that.selectedTransactions) && notSelectedTransactions.equals(that.notSelectedTransactions) && receipts.equals(that.receipts); @@ -187,14 +187,14 @@ public int hashCode() { notSelectedTransactions, receipts, cumulativeGasUsed, - cumulativeDataGasUsed); + cumulativeBlobGasUsed); } public String toTraceLog() { return "cumulativeGasUsed=" + cumulativeGasUsed - + ", cumulativeDataGasUsed=" - + cumulativeDataGasUsed + + ", cumulativeBlobGasUsed=" + + cumulativeBlobGasUsed + ", selectedTransactions=" + selectedTransactions.stream() .map(Transaction::toTraceLog) @@ -219,7 +219,7 @@ public String toTraceLog() { 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; @@ -238,7 +238,7 @@ public BlockTransactionSelector( final Double minBlockOccupancyRatio, final Supplier isCancelled, final Address miningBeneficiary, - final Wei dataGasPrice, + final Wei blobGasPrice, final FeeMarket feeMarket, final GasCalculator gasCalculator, final GasLimitCalculator gasLimitCalculator, @@ -253,7 +253,7 @@ public BlockTransactionSelector( this.minTransactionGasPrice = minTransactionGasPrice; this.minBlockOccupancyRatio = minBlockOccupancyRatio; this.miningBeneficiary = miningBeneficiary; - this.dataGasPrice = dataGasPrice; + this.blobGasPrice = blobGasPrice; this.feeMarket = feeMarket; this.gasCalculator = gasCalculator; this.gasLimitCalculator = gasLimitCalculator; @@ -354,7 +354,7 @@ private TransactionSelectionResult evaluateTransaction(final Transaction transac blockHashLookup, false, TransactionValidationParams.mining(), - dataGasPrice); + blobGasPrice); if (!effectiveResult.isInvalid()) { @@ -379,10 +379,10 @@ private TransactionSelectionResult evaluateTransaction(final Transaction transac transactionReceiptFactory.create( transaction.getType(), effectiveResult, worldState, cumulativeGasUsed); - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long blobGasUsed = gasCalculator.blobGasCost(transaction.getBlobCount()); transactionSelectionResults.updateSelected( - transaction, receipt, gasUsedByTransaction, dataGasUsed); + transaction, receipt, gasUsedByTransaction, blobGasUsed); LOG.atTrace() .setMessage("Selected {} for block creation") @@ -406,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; } } @@ -469,15 +469,15 @@ private boolean isTransientValidationError(final TransactionInvalidReason invali } 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/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java index b16cc1e9d6c..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 @@ -32,8 +32,8 @@ 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.DataGas; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.TransactionType; @@ -274,7 +274,7 @@ void withNoProcessorAndWithdrawals_WithdrawalsAreNotProcessed() { @Test public void computesGasUsageFromIncludedTransactions() { final KeyPair senderKeys = SignatureAlgorithmFactory.getInstance().generateKeyPair(); - final AbstractBlockCreator blockCreator = blockCreatorWithDataGasSupport(); + final AbstractBlockCreator blockCreator = blockCreatorWithBlobGasSupport(); BlobTestFixture blobTestFixture = new BlobTestFixture(); BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(6); TransactionTestFixture ttf = new TransactionTestFixture(); @@ -283,7 +283,7 @@ public void computesGasUsageFromIncludedTransactions() { .type(TransactionType.BLOB) .chainId(Optional.of(BigInteger.valueOf(42))) .maxFeePerGas(Optional.of(Wei.of(15))) - .maxFeePerDataGas(Optional.of(Wei.of(128))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) .maxPriorityFeePerGas(Optional.of(Wei.of(1))) .versionedHashes(Optional.of(bwc.getVersionedHashes())) .createTransaction(senderKeys); @@ -297,13 +297,13 @@ public void computesGasUsageFromIncludedTransactions() { Optional.empty(), 1L, false); - long dataGasUsage = blockCreationResult.getBlock().getHeader().getGasUsed(); - assertThat(dataGasUsage).isNotZero(); - DataGas excessDataGas = blockCreationResult.getBlock().getHeader().getExcessDataGas().get(); - assertThat(excessDataGas).isNotNull(); + long blobGasUsage = blockCreationResult.getBlock().getHeader().getGasUsed(); + assertThat(blobGasUsage).isNotZero(); + BlobGas excessBlobGas = blockCreationResult.getBlock().getHeader().getExcessBlobGas().get(); + assertThat(excessBlobGas).isNotNull(); } - private AbstractBlockCreator blockCreatorWithDataGasSupport() { + private AbstractBlockCreator blockCreatorWithBlobGasSupport() { final ProtocolSpecAdapters protocolSpecAdapters = ProtocolSpecAdapters.create( 0, 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 e8d008df890..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 @@ -630,7 +630,7 @@ 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( @@ -644,7 +644,7 @@ protected BlockTransactionSelector createBlockSelector( minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, - dataGasPrice, + blobGasPrice, getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant(), @@ -658,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 = @@ -673,7 +673,7 @@ protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, - dataGasPrice, + blobGasPrice, getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant(), 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 05605d6c3b8..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,7 +16,7 @@ public interface GasLimitCalculator { - static final long DATA_GAS_LIMIT = 786432; + static final long BLOB_GAS_LIMIT = 786432; long nextGasLimit(long currentGasLimit, long targetGasLimit, long newBlockNumber); @@ -24,7 +24,7 @@ static GasLimitCalculator constant() { return (currentGasLimit, targetGasLimit, newBlockNumber) -> currentGasLimit; } - default long currentDataGasLimit() { - return DATA_GAS_LIMIT; + default long currentBlobGasLimit() { + return BLOB_GAS_LIMIT; } } 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 959559a9af5..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,7 +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.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.Block; @@ -168,8 +168,8 @@ private static BlockHeader buildHeader( .blockHeaderFunctions(ScheduleBasedBlockHeaderFunctions.create(protocolSchedule)) .baseFee(genesis.getGenesisBaseFeePerGas().orElse(null)) .withdrawalsRoot(isShanghaiAtGenesis(genesis) ? Hash.EMPTY_TRIE_HASH : null) - .dataGasUsed(isCancunAtGenesis(genesis) ? parseDataGasUsed(genesis) : null) - .excessDataGas(isCancunAtGenesis(genesis) ? parseExcessDataGas(genesis) : null) + .blobGasUsed(isCancunAtGenesis(genesis) ? parseBlobGasUsed(genesis) : null) + .excessBlobGas(isCancunAtGenesis(genesis) ? parseExcessBlobGas(genesis) : null) .depositsRoot(isExperimentalEipsTimeAtGenesis(genesis) ? Hash.EMPTY_TRIE_HASH : null) .buildBlockHeader(); } @@ -220,16 +220,16 @@ private static long parseNonce(final GenesisConfigFile genesis) { return withNiceErrorMessage("nonce", genesis.getNonce(), GenesisState::parseUnsignedLong); } - private static long parseDataGasUsed(final GenesisConfigFile genesis) { + private static long parseBlobGasUsed(final GenesisConfigFile genesis) { return withNiceErrorMessage( - "dataGasUsed", genesis.getDataGasUsed(), GenesisState::parseUnsignedLong); + "blobGasUsed", genesis.getBlobGasUsed(), GenesisState::parseUnsignedLong); } - private static DataGas parseExcessDataGas(final GenesisConfigFile genesis) { - long excessDataGas = + private static BlobGas parseExcessBlobGas(final GenesisConfigFile genesis) { + long excessBlobGas = withNiceErrorMessage( - "excessDataGas", genesis.getExcessDataGas(), GenesisState::parseUnsignedLong); - return DataGas.of(excessDataGas); + "excessBlobGas", genesis.getExcessBlobGas(), GenesisState::parseUnsignedLong); + return BlobGas.of(excessBlobGas); } private static long parseUnsignedLong(final String value) { 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 86bfabe4aee..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,8 +62,8 @@ public BlockHeader( final Bytes32 mixHashOrPrevRandao, final long nonce, final Hash withdrawalsRoot, - final long dataGasUsed, - final DataGas excessDataGas, + final long blobGasUsed, + final BlobGas excessBlobGas, final Hash depositsRoot, final BlockHeaderFunctions blockHeaderFunctions, final Optional privateLogsBloom) { @@ -84,8 +84,8 @@ public BlockHeader( baseFee, mixHashOrPrevRandao, withdrawalsRoot, - dataGasUsed, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot); this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); @@ -110,8 +110,8 @@ public BlockHeader( final Bytes32 mixHashOrPrevRandao, final long nonce, final Hash withdrawalsRoot, - final Long dataGasUsed, - final DataGas excessDataGas, + final Long blobGasUsed, + final BlobGas excessBlobGas, final Hash depositsRoot, final BlockHeaderFunctions blockHeaderFunctions) { super( @@ -131,8 +131,8 @@ public BlockHeader( baseFee, mixHashOrPrevRandao, withdrawalsRoot, - dataGasUsed, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot); this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); @@ -216,9 +216,9 @@ public void writeTo(final RLPOutput out) { if (withdrawalsRoot != null) { out.writeBytes(withdrawalsRoot); } - if (excessDataGas.isPresent() && dataGasUsed.isPresent()) { - out.writeLongScalar(dataGasUsed.get()); - out.writeUInt64Scalar(excessDataGas.get()); + if (excessBlobGas.isPresent() && blobGasUsed.isPresent()) { + out.writeLongScalar(blobGasUsed.get()); + out.writeUInt64Scalar(excessBlobGas.get()); } if (depositsRoot != null) { out.writeBytes(depositsRoot); @@ -249,9 +249,9 @@ public static BlockHeader readFrom( !(input.isEndOfCurrentList() || input.isZeroLengthString()) ? Hash.wrap(input.readBytes32()) : null; - final Long dataGasUsed = !input.isEndOfCurrentList() ? input.readLongScalar() : null; - final DataGas excessDataGas = - !input.isEndOfCurrentList() ? DataGas.of(input.readLongScalar()) : 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(); @@ -273,8 +273,8 @@ public static BlockHeader readFrom( mixHashOrPrevRandao, nonce, withdrawalHashRoot, - dataGasUsed, - excessDataGas, + blobGasUsed, + excessBlobGas, depositHashRoot, blockHeaderFunctions); } @@ -320,8 +320,8 @@ public String toString() { if (withdrawalsRoot != null) { sb.append("withdrawalsRoot=").append(withdrawalsRoot).append(", "); } - dataGasUsed.ifPresent(aLong -> sb.append("dataGasUsed=").append(aLong).append(", ")); - excessDataGas.ifPresent(dataGas -> sb.append("excessDataGas=").append(dataGas).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); } @@ -352,8 +352,8 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH .getWithdrawalsRoot() .map(h -> Hash.fromHexString(h.toHexString())) .orElse(null), - pluginBlockHeader.getDataGasUsed().map(Long::longValue).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 41536ca964e..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,8 +73,8 @@ public class BlockHeaderBuilder { // instead of an invalid identifier such as -1. private OptionalLong nonce = OptionalLong.empty(); - private Long dataGasUsed = null; - private DataGas excessDataGas = null; + private Long blobGasUsed = null; + private BlobGas excessBlobGas = null; public static BlockHeaderBuilder create() { return new BlockHeaderBuilder(); @@ -120,8 +120,8 @@ public static BlockHeaderBuilder fromHeader(final BlockHeader header) { .nonce(header.getNonce()) .prevRandao(header.getPrevRandao().orElse(null)) .withdrawalsRoot(header.getWithdrawalsRoot().orElse(null)) - .dataGasUsed(header.getDataGasUsed().orElse(null)) - .excessDataGas(header.getExcessDataGas().orElse(null)) + .blobGasUsed(header.getBlobGasUsed().orElse(null)) + .excessBlobGas(header.getExcessBlobGas().orElse(null)) .depositsRoot(header.getDepositsRoot().orElse(null)); } @@ -144,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; @@ -172,8 +172,8 @@ public BlockHeader buildBlockHeader() { mixHashOrPrevRandao, nonce.getAsLong(), withdrawalsRoot, - dataGasUsed, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot, blockHeaderFunctions); } @@ -190,8 +190,8 @@ public ProcessableBlockHeader buildProcessableBlockHeader() { timestamp, baseFee, mixHashOrPrevRandao, - dataGasUsed, - excessDataGas); + blobGasUsed, + excessBlobGas); } public SealableBlockHeader buildSealableBlockHeader() { @@ -214,8 +214,8 @@ public SealableBlockHeader buildSealableBlockHeader() { baseFee, mixHashOrPrevRandao, withdrawalsRoot, - dataGasUsed, - excessDataGas, + blobGasUsed, + excessBlobGas, depositsRoot); } @@ -256,8 +256,8 @@ public BlockHeaderBuilder populateFrom(final ProcessableBlockHeader processableB timestamp(processableBlockHeader.getTimestamp()); baseFee(processableBlockHeader.getBaseFee().orElse(null)); processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); - processableBlockHeader.getDataGasUsed().ifPresent(this::dataGasUsed); - processableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); + processableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed); + processableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); return this; } @@ -279,8 +279,8 @@ public BlockHeaderBuilder populateFrom(final SealableBlockHeader sealableBlockHe baseFee(sealableBlockHeader.getBaseFee().orElse(null)); sealableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); withdrawalsRoot(sealableBlockHeader.getWithdrawalsRoot().orElse(null)); - sealableBlockHeader.getDataGasUsed().ifPresent(this::dataGasUsed); - sealableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); + sealableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed); + sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); depositsRoot(sealableBlockHeader.getDepositsRoot().orElse(null)); return this; } @@ -402,13 +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 dataGasUsed(final Long dataGasUsed) { - this.dataGasUsed = dataGasUsed; + public BlockHeaderBuilder blobGasUsed(final Long blobGasUsed) { + this.blobGasUsed = blobGasUsed; return this; } } 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 fd2318a85d2..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,10 +44,10 @@ public class ProcessableBlockHeader implements BlockValues { protected final Wei baseFee; // prevRandao is included for post-merge blocks protected final Bytes32 mixHashOrPrevRandao; - // dataGasUsed is included for Cancun - protected final Optional dataGasUsed; - // excessDataGas is included for Cancun - protected final Optional excessDataGas; + // blobGasUsed is included for Cancun + protected final Optional blobGasUsed; + // excessBlogGas is included for Cancun + protected final Optional excessBlobGas; protected ProcessableBlockHeader( final Hash parentHash, @@ -58,8 +58,8 @@ protected ProcessableBlockHeader( final long timestamp, final Wei baseFee, final Bytes32 mixHashOrPrevRandao, - final Long dataGasUsed, - final DataGas excessDataGas) { + final Long blobGasUsed, + final BlobGas excessBlobGas) { this.parentHash = parentHash; this.coinbase = coinbase; this.difficulty = difficulty; @@ -68,8 +68,8 @@ protected ProcessableBlockHeader( this.timestamp = timestamp; this.baseFee = baseFee; this.mixHashOrPrevRandao = mixHashOrPrevRandao; - this.dataGasUsed = Optional.ofNullable(dataGasUsed); - this.excessDataGas = Optional.ofNullable(excessDataGas); + this.blobGasUsed = Optional.ofNullable(blobGasUsed); + this.excessBlobGas = Optional.ofNullable(excessBlobGas); } /** @@ -168,12 +168,12 @@ public Optional getPrevRandao() { return Optional.ofNullable(mixHashOrPrevRandao); } - public Optional getExcessDataGas() { - return excessDataGas; + public Optional getExcessBlobGas() { + return excessBlobGas; } - public Optional getDataGasUsed() { - return dataGasUsed; + 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 8b76768eb7e..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,8 +62,8 @@ protected SealableBlockHeader( final Wei baseFee, final Bytes32 mixHashOrPrevRandao, final Hash withdrawalsRoot, - final Long dataGasUsed, - final DataGas excessDataGas, + final Long blobGasUsed, + final BlobGas excessBlobGas, final Hash depositsRoot) { super( parentHash, @@ -74,8 +74,8 @@ protected SealableBlockHeader( timestamp, baseFee, mixHashOrPrevRandao, - dataGasUsed, - 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 798544c63ca..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 @@ -83,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; @@ -139,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 @@ -160,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, @@ -188,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()) { @@ -200,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; @@ -208,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; @@ -230,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, @@ -246,7 +246,7 @@ public Transaction( gasPrice, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -361,7 +361,7 @@ public Transaction( final Bytes payload, final Address sender, final Optional chainId, - final Optional maxFeePerDataGas, + final Optional maxFeePerBlobGas, final Optional> versionedHashes, final Optional blobsWithCommitments) { this( @@ -369,7 +369,7 @@ public Transaction( Optional.of(gasPrice), Optional.empty(), Optional.empty(), - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -422,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; } /** @@ -439,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) @@ -604,7 +604,7 @@ private Bytes32 getOrComputeSenderRecoveryHash() { gasPrice.orElse(null), maxPriorityFeePerGas.orElse(null), maxFeePerGas.orElse(null), - maxFeePerDataGas.orElse(null), + maxFeePerBlobGas.orElse(null), gasLimit, to, value, @@ -706,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); } /** @@ -721,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; @@ -743,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; @@ -763,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()); } /** @@ -826,7 +826,7 @@ 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, @@ -861,7 +861,7 @@ private static Bytes32 computeSenderRecoveryHash( nonce, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -974,7 +974,7 @@ 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, @@ -998,7 +998,7 @@ private static Bytes blobPreimage( chainId, accessList, rlpOutput); - rlpOutput.writeUInt256Scalar(maxFeePerDataGas); + rlpOutput.writeUInt256Scalar(maxFeePerBlobGas); BlobTransactionEncoder.writeBlobVersionedHashes(rlpOutput, versionedHashes); rlpOutput.endList(); }); @@ -1036,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) @@ -1052,7 +1052,7 @@ public int hashCode() { gasPrice, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, @@ -1081,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(", "); @@ -1118,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(", "); @@ -1146,7 +1146,7 @@ public static class Builder { protected Wei maxPriorityFeePerGas; protected Wei maxFeePerGas; - protected Wei maxFeePerDataGas; + protected Wei maxFeePerBlobGas; protected long gasLimit = -1L; @@ -1197,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; } @@ -1275,7 +1275,7 @@ public Transaction build() { Optional.ofNullable(gasPrice), Optional.ofNullable(maxPriorityFeePerGas), Optional.ofNullable(maxFeePerGas), - Optional.ofNullable(maxFeePerDataGas), + Optional.ofNullable(maxFeePerBlobGas), gasLimit, to, value, @@ -1305,7 +1305,7 @@ SECPSignature computeSignature(final KeyPair keys) { gasPrice, maxPriorityFeePerGas, maxFeePerGas, - maxFeePerDataGas, + maxFeePerBlobGas, gasLimit, to, value, 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 index d9dd82b567c..b2f030f9d61 100644 --- 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 @@ -79,7 +79,7 @@ private static void readTransactionPayloadInner( accessListEntryRLPInput.leaveList(); return accessListEntry; })) - .maxFeePerDataGas(Wei.of(input.readUInt256Scalar())) + .maxFeePerBlobGas(Wei.of(input.readUInt256Scalar())) .versionedHashes( input.readList(versionedHashes -> new VersionedHash(versionedHashes.readBytes32()))); 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 index 63ee8fbb8a8..6df9baed920 100644 --- 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 @@ -43,7 +43,7 @@ public static void encodeEIP4844(final Transaction transaction, final RLPOutput out.writeUInt256Scalar(transaction.getValue()); out.writeBytes(transaction.getPayload()); TransactionEncoder.writeAccessList(out, transaction.getAccessList()); - out.writeUInt256Scalar(transaction.getMaxFeePerDataGas().orElseThrow()); + out.writeUInt256Scalar(transaction.getMaxFeePerBlobGas().orElseThrow()); out.startList(); transaction .getVersionedHashes() 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 aad41dd9fea..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 @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.core.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; @@ -62,18 +62,18 @@ private static BigInteger fakeExponential( return output.divide(denominator); } - static TransactionPriceCalculator dataGas( - final int minDataGasPrice, - final int dataGasPriceUpdateFraction, - final DataGas excessDataGas) { + static TransactionPriceCalculator blobGas( + final int minBlobGasPrice, + final int blobGasPriceUpdateFraction, + final BlobGas excessBlobGas) { return ((transaction, baseFee) -> { - final var dataGasPrice = + final var blobGasPrice = Wei.of( fakeExponential( - BigInteger.valueOf(minDataGasPrice), - excessDataGas.toBigInteger(), - BigInteger.valueOf(dataGasPriceUpdateFraction))); - return dataGasPrice; + 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 15aca473829..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,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet; -import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.TransactionType; @@ -117,14 +117,14 @@ public BlockProcessingResult processBlock( Optional maybeParentHeader = blockchain.getBlockHeader(blockHeader.getParentHash()); - Wei dataGasPrice = + Wei blobGasPrice = maybeParentHeader .map( (parentHeader) -> protocolSpec .getFeeMarket() - .dataPricePerGas( - calculateExcessDataGasForParent(protocolSpec, parentHeader))) + .blobGasPricePerGas( + calculateExcessBlobGasForParent(protocolSpec, parentHeader))) .orElse(Wei.ZERO); final TransactionProcessingResult result = @@ -139,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 84841da9bc1..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 = 786432L; + 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/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 3d58cccae22..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,10 +20,10 @@ 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; -import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.DataGasValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ExtraDataMaxLengthValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasUsageValidationRule; @@ -200,6 +200,6 @@ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMa public static BlockHeaderValidator.Builder cancunBlockHeaderValidator(final FeeMarket feeMarket) { return mergeBlockHeaderValidator(feeMarket) - .addRule(new DataGasValidationRule(new CancunGasCalculator())); + .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 1299dc9d01d..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 @@ -656,9 +656,9 @@ 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 + // gas limit with EIP-4844 max blob gas per block .gasLimitCalculatorBuilder( feeMarket -> new CancunTargetingGasLimitCalculator( @@ -696,7 +696,7 @@ static ProtocolSpecBuilder cancunDefinition( stackSizeLimit, feeMarket, CoinbaseFeePriceCalculator.eip1559())) - // change to check for max data gas per block for EIP-4844 + // change to check for max blob gas per block for EIP-4844 .transactionValidatorFactoryBuilder( (gasCalculator, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( 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 64a8450cd38..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 @@ -124,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, @@ -136,7 +136,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, transactionValidationParams, null, - dataGasPrice); + blobGasPrice); } /** @@ -166,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, @@ -178,7 +178,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, transactionValidationParams, null, - dataGasPrice); + blobGasPrice); } /** @@ -203,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, @@ -215,7 +215,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, ImmutableTransactionValidationParams.builder().build(), null, - dataGasPrice); + blobGasPrice); } /** @@ -242,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, @@ -254,7 +254,7 @@ public TransactionProcessingResult processTransaction( isPersistingPrivateState, transactionValidationParams, null, - dataGasPrice); + blobGasPrice); } public TransactionProcessingResult processTransaction( @@ -268,7 +268,7 @@ 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); @@ -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 {} ({} -> {})", @@ -346,7 +346,7 @@ public TransactionProcessingResult processTransaction( transaction.getGasLimit(), intrinsicGas, accessListGas, - dataGas); + blobGas); final WorldUpdater worldUpdater = worldState.updater(); final ImmutableMap.Builder contextVariablesBuilder = 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 01d35737e41..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 @@ -51,7 +51,7 @@ */ public class MainnetTransactionValidator implements TransactionValidator { - private final byte BLOB_COMMITMENT_VERSION_KZG = 0x01; + private static final byte BLOB_COMMITMENT_VERSION_KZG = 0x01; private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; @@ -155,24 +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_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())); } } 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_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())); } } @@ -207,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, 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 8a570fecd85..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(3338477); + 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 dataPricePerGas(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/ExcessDataGasCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java similarity index 68% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessDataGasCalculator.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java index 75e179595a5..f6372097b7f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessDataGasCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java @@ -14,29 +14,29 @@ */ package org.hyperledger.besu.ethereum.mainnet.feemarket; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -/** Calculates the excess data gas for a parent block header. */ -public class ExcessDataGasCalculator { +/** Calculates the excess blob gas for a parent block header. */ +public class ExcessBlobGasCalculator { /** - * public class ExcessDataGasCalculator { /** Calculates the excess data gas for a parent block + * 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 data gas. + * @return The excess blob gas. */ - public static DataGas calculateExcessDataGasForParent( + public static BlobGas calculateExcessBlobGasForParent( final ProtocolSpec protocolSpec, final BlockHeader parentHeader) { // Blob Data Excess long headerExcess = protocolSpec .getGasCalculator() - .computeExcessDataGas( - parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), - parentHeader.getDataGasUsed().orElse(0L)); - return DataGas.of(headerExcess); + .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 a44e7f629e4..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 dataPricePerGas(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/headervalidationrules/DataGasValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java similarity index 60% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRule.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java index 2849c7a99e0..e58d378562f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; -import org.hyperledger.besu.datatypes.DataGas; +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; @@ -22,35 +22,35 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** Validation rule to check if the block header's excess data gas matches the calculated value. */ -public class DataGasValidationRule implements DetachedBlockHeaderValidationRule { +/** 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(DataGasValidationRule.class); + private static final Logger LOG = LoggerFactory.getLogger(BlobGasValidationRule.class); private final GasCalculator gasCalculator; - public DataGasValidationRule(final GasCalculator gasCalculator) { + public BlobGasValidationRule(final GasCalculator gasCalculator) { this.gasCalculator = gasCalculator; } /** - * Validates the block header by checking if the header's excess data gas matches the calculated + * 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 headerExcessDataGas = header.getExcessDataGas().map(DataGas::toLong).orElse(0L); - long parentExcessDataGas = parent.getExcessDataGas().map(DataGas::toLong).orElse(0L); - long parentDataGasUsed = parent.getDataGasUsed().orElse(0L); + 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 calculatedExcessDataGas = - gasCalculator.computeExcessDataGas(parentExcessDataGas, parentDataGasUsed); + long calculatedExcessBlobGas = + gasCalculator.computeExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed); - if (headerExcessDataGas != calculatedExcessDataGas) { + if (headerExcessBlobGas != calculatedExcessBlobGas) { LOG.info( - "Invalid block header: header excessDataGas {} and calculated excessDataGas {} do not match", - headerExcessDataGas, - calculatedExcessDataGas); + "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/transaction/TransactionInvalidReason.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java index e013186e2b5..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,7 +40,7 @@ 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, 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 22c4ac4554f..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,13 +14,13 @@ */ package org.hyperledger.besu.ethereum.transaction; -import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessDataGasCalculator.calculateExcessDataGasForParent; +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; @@ -233,13 +233,13 @@ public Optional processWithWorldUpdater( final Optional maybeParentHeader = blockchain.getBlockHeader(blockHeaderToProcess.getParentHash()); - final Wei dataGasPrice = + final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPricePerGas( + .blobGasPricePerGas( maybeParentHeader - .map(parent -> calculateExcessDataGasForParent(protocolSpec, parent)) - .orElse(DataGas.ZERO)); + .map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent)) + .orElse(BlobGas.ZERO)); final Transaction transaction = maybeTransaction.get(); final TransactionProcessingResult result = @@ -255,7 +255,7 @@ public Optional processWithWorldUpdater( false, transactionValidationParams, operationTracer, - dataGasPrice); + blobGasPrice); return Optional.of(new TransactionSimulatorResult(transaction, result)); } 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 df473612ccc..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 @@ -442,7 +442,7 @@ private Transaction blobTransaction(final Bytes payload, final Address to) { .value(Wei.of(positiveLong())) .payload(payload) .chainId(BigInteger.ONE) - .maxFeePerDataGas(Wei.of(1)) + .maxFeePerBlobGas(Wei.of(1)) .versionedHashes(List.of(VersionedHash.DEFAULT_VERSIONED_HASH)) .signAndBuild(generateKeyPair()); } @@ -674,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(); @@ -874,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 9f23a0d044d..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,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.mainnet.MainnetBlockHeaderFunctions; @@ -52,8 +52,8 @@ public class BlockHeaderTestFixture { private Optional withdrawalsRoot = Optional.empty(); private Optional depositsRoot = Optional.empty(); private BlockHeaderFunctions blockHeaderFunctions = new MainnetBlockHeaderFunctions(); - private Optional excessDataGas = Optional.empty(); - private Optional dataGasUsed = Optional.empty(); + private Optional excessBlobGas = Optional.empty(); + private Optional blobGasUsed = Optional.empty(); public BlockHeader buildHeader() { final BlockHeaderBuilder builder = BlockHeaderBuilder.create(); @@ -75,8 +75,8 @@ public BlockHeader buildHeader() { builder.mixHash(mixHash); builder.nonce(nonce); withdrawalsRoot.ifPresent(builder::withdrawalsRoot); - excessDataGas.ifPresent(builder::excessDataGas); - dataGasUsed.ifPresent(builder::dataGasUsed); + excessBlobGas.ifPresent(builder::excessBlobGas); + blobGasUsed.ifPresent(builder::blobGasUsed); depositsRoot.ifPresent(builder::depositsRoot); builder.blockHeaderFunctions(blockHeaderFunctions); @@ -178,13 +178,13 @@ public BlockHeaderTestFixture depositsRoot(final Hash depositsRoot) { return this; } - public BlockHeaderTestFixture excessDataGas(final DataGas excessDataGas) { - this.excessDataGas = Optional.ofNullable(excessDataGas); + public BlockHeaderTestFixture excessBlobGas(final BlobGas excessBlobGas) { + this.excessBlobGas = Optional.ofNullable(excessBlobGas); return this; } - public BlockHeaderTestFixture dataGasUsed(final Long dataGasUsed) { - this.dataGasUsed = Optional.ofNullable(dataGasUsed); + public BlockHeaderTestFixture blobGasUsed(final Long blobGasUsed) { + this.blobGasUsed = Optional.ofNullable(blobGasUsed); return this; } 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 9838ca29204..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,12 +124,12 @@ public Hash getBlockHash() { } @Override - public Optional getExcessDataGas() { + public Optional getExcessBlobGas() { return Optional.empty(); } @Override - public Optional getDataGasUsed() { + public Optional getBlobGasUsed() { return Optional.empty(); } } 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 1ba60c3cb55..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 @@ -49,7 +49,7 @@ 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(); @@ -84,7 +84,7 @@ 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.maxFeePerBlobGas(maxFeePerBlobGas.orElse(Wei.ONE)); builder.versionedHashes( versionedHashes.orElse(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))); blobs.ifPresent( @@ -156,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; } 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 e3f0ffaa74c..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 @@ -95,7 +95,7 @@ public class LogRollingTests { Hash.ZERO, 0, null, - null, // dataGasUSed + null, // blobGasUSed null, null, new MainnetBlockHeaderFunctions()); @@ -118,7 +118,7 @@ public class LogRollingTests { Hash.ZERO, 0, null, - null, // dataGasUsed + null, // blobGasUsed null, null, new MainnetBlockHeaderFunctions()); 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 dd81068878b..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 @@ -69,7 +69,7 @@ public void zeroBlobTransactionIsInvalid() { .versionedHashes(Optional.of(List.of())) .maxFeePerGas(Optional.of(Wei.of(5))) .maxPriorityFeePerGas(Optional.of(Wei.of(5))) - .maxFeePerDataGas(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/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index e7a9028a497..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 @@ -498,7 +498,7 @@ public void shouldRejectContractCreateWithBlob() { .type(TransactionType.BLOB) .chainId(Optional.of(BigInteger.ONE)) .maxFeePerGas(Optional.of(Wei.of(15))) - .maxFeePerDataGas(Optional.of(Wei.of(128))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) .maxPriorityFeePerGas(Optional.of(Wei.of(1))) .blobsWithCommitments( Optional.of( @@ -523,7 +523,7 @@ public void shouldRejectContractCreateWithBlob() { @Test public void shouldAcceptTransactionWithAtLeastOneBlob() { - when(gasCalculator.dataGasCost(anyInt())).thenReturn(2L); + when(gasCalculator.blobGasCost(anyInt())).thenReturn(2L); final TransactionValidator validator = createTransactionValidator( gasCalculator, @@ -542,7 +542,7 @@ public void shouldAcceptTransactionWithAtLeastOneBlob() { .type(TransactionType.BLOB) .chainId(Optional.of(BigInteger.ONE)) .maxFeePerGas(Optional.of(Wei.of(15))) - .maxFeePerDataGas(Optional.of(Wei.of(128))) + .maxFeePerBlobGas(Optional.of(Wei.of(128))) .maxPriorityFeePerGas(Optional.of(Wei.of(1))) .blobsWithCommitments(Optional.of(bwc)) .versionedHashes(Optional.of(bwc.getVersionedHashes())) 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 index 9c3636c30e4..2394d66da51 100644 --- 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 @@ -17,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import java.util.ArrayList; import java.util.List; @@ -27,39 +27,39 @@ class CancunFeeMarketTest { - private static final int DATA_GAS_PER_BLOB = 131072; + private static final int BLOB_GAS_PER_BLOB = 131072; @Test void dataPricePerGas() { CancunFeeMarket cancunFeeMarket = new CancunFeeMarket(0, Optional.empty()); - // when no excess data gas, data price per gas is 1 - assertEquals(1, cancunFeeMarket.dataPricePerGas(DataGas.ZERO).getAsBigInteger().intValue()); + // when no excess blob gas, data price per gas is 1 + assertEquals(1, cancunFeeMarket.blobGasPricePerGas(BlobGas.ZERO).getAsBigInteger().intValue()); - record DataGasPricing(long excess, long price) {} - List testVector = new ArrayList<>(); + record BlobGasPricing(long excess, long price) {} + List testVector = new ArrayList<>(); int numBlobs = 1; long price = 1; while (price <= 1000) { - price = dataGasPrice(DataGas.of(numBlobs * DATA_GAS_PER_BLOB)); - var testCase = new DataGasPricing(numBlobs * DATA_GAS_PER_BLOB, price); + 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( - dataGasPricing -> { + blobGasPricing -> { assertEquals( - dataGasPricing.price, + blobGasPricing.price, cancunFeeMarket - .dataPricePerGas(DataGas.of(dataGasPricing.excess)) + .blobGasPricePerGas(BlobGas.of(blobGasPricing.excess)) .getAsBigInteger() .intValue()); }); } - private long dataGasPrice(final DataGas excess) { + 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/ZeroBaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java index 44839c437f7..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,7 +18,7 @@ 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; @@ -147,6 +147,6 @@ public void implementsDataFeedShouldReturnFalse() { @Test public void dataPriceShouldReturnsZero() { - assertThat(zeroBaseFeeMarket.dataPricePerGas(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/DataGasValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java similarity index 62% rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRuleTest.java rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java index d5831766298..34f7079be10 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/DataGasValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java @@ -17,7 +17,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.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; @@ -25,54 +25,54 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -/** Tests for the {@link DataGasValidationRule} class. */ -public class DataGasValidationRuleTest { +/** Tests for the {@link BlobGasValidationRule} class. */ +public class BlobGasValidationRuleTest { private CancunGasCalculator gasCalculator; - private DataGasValidationRule dataGasValidationRule; + private BlobGasValidationRule blobGasValidationRule; @BeforeEach public void setUp() { gasCalculator = new CancunGasCalculator(); - dataGasValidationRule = new DataGasValidationRule(gasCalculator); + blobGasValidationRule = new BlobGasValidationRule(gasCalculator); } - /** Tests that the header data gas matches the calculated data gas and passes validation. */ + /** Tests that the header blob gas matches the calculated blob gas and passes validation. */ @Test - public void validateHeader_DataGasMatchesCalculated_SuccessValidation() { - long target = gasCalculator.getTargetDataGasPerBlock(); + public void validateHeader_BlobGasMatchesCalculated_SuccessValidation() { + long target = gasCalculator.getTargetBlobGasPerBlock(); // Create parent header final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); - parentBuilder.excessDataGas(DataGas.of(1L)); - parentBuilder.dataGasUsed(target); + parentBuilder.excessBlobGas(BlobGas.of(1L)); + parentBuilder.blobGasUsed(target); final BlockHeader parentHeader = parentBuilder.buildHeader(); - // Create block header with matching excessDataGas + // Create block header with matching excessBlobGas final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); - headerBuilder.excessDataGas(DataGas.of(1L)); + headerBuilder.excessBlobGas(BlobGas.of(1L)); final BlockHeader header = headerBuilder.buildHeader(); - assertThat(dataGasValidationRule.validate(header, parentHeader)).isTrue(); + assertThat(blobGasValidationRule.validate(header, parentHeader)).isTrue(); } /** - * Tests that the header data gas is different from the calculated data gas and fails validation. + * Tests that the header blob gas is different from the calculated blob gas and fails validation. */ @Test - public void validateHeader_DataGasDifferentFromCalculated_FailsValidation() { - long target = gasCalculator.getTargetDataGasPerBlock(); + public void validateHeader_BlobGasDifferentFromCalculated_FailsValidation() { + long target = gasCalculator.getTargetBlobGasPerBlock(); // Create parent header final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); - parentBuilder.excessDataGas(DataGas.of(1L)); - parentBuilder.dataGasUsed(target); + parentBuilder.excessBlobGas(BlobGas.of(1L)); + parentBuilder.blobGasUsed(target); final BlockHeader parentHeader = parentBuilder.buildHeader(); - // Create block header with different excessDataGas + // Create block header with different excessBlobGas final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeader header = headerBuilder.buildHeader(); - assertThat(dataGasValidationRule.validate(header, parentHeader)).isFalse(); + assertThat(blobGasValidationRule.validate(header, parentHeader)).isFalse(); } } 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 index f642ed46d6a..452c23fa2b9 100644 --- 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 @@ -8,7 +8,7 @@ "GasLimit": 100000, "GasPrice": "1000", "PriorityGasPrice": "50", - "MaxFeePerDataGas": "100", + "MaxFeePerBlobGas": "100", "Data": "0x77918d0c4153776b" }, "RawEncodedTransaction": "0x033c00000076010000a6010000b0b4fa487696b3e1ab9de18f8e1d295e46b1048a68e18787145f5bc1e34faa6178b4018747674c3849fa7c1d38f2f07b4500000000935bdf0c90c47aaaf38ae7eed1380cfecea8c0a2cc5c93a4cbbba10976e306256a2f48215abc90b8edf7cdcfe226eb5841d86fa19cd4b5446dc075376fd59b0c330500000000000000000000000000000000000000000000000000000000000001000000000000003200000000000000000000000000000000000000000000000000000000000000e803000000000000000000000000000000000000000000000000000000000000a086010000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000006400000000000000000000000000000000000000000000000000000000000000d50000000145ae5777c9b35eb16280e423b0d7c91c06c66b5801f4af1847885b145b1a91f61c6c4dc13be1239debecf751101ee69c16f58904b8f1de4f6734fbcb617df946d87d8dd210440bb33ff8d84e86aa08660ee7beec27127438f5882f5f9b74fecef38c437c77918d0c4153776b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" @@ -22,7 +22,7 @@ "GasLimit": 50000, "GasPrice": "1234", "PriorityGasPrice": "100", - "MaxFeePerDataGas": "200", + "MaxFeePerBlobGas": "200", "Data": "0x61f1628061be533586f64f50678a793e64a207a5df408217ed91c94f3c6f61bf6e2f6ff982b7ac3f300face1b52ae3fc68ee030fdc3150d73a056bd4df661059c6d1cb08ea2b39d0d49b0efaa75b8b61fb7f2b9caca6896aea156ed0304701796c517e2b010e387fefc702dabc6b4d2c732a173d33e0c272701e4f8668bad602" }, "RawEncodedTransaction": "0x033c00000076010000a6010000b6fabe6947368cfe7c5ac38eab67c0a3d5013848cb3b6600e0a0e205c1719577f5cd89b9e6c256ef9bc131d7550b9a2945000000002548c5fb3971907ef5a3ec7e092ff4abc602dfa5859805cba9ec3a725784f864954c50ef43cc745af6631688c6b819881eb3dab130cef3aee2bcb529f07de919330500000000000000000000000000000000000000000000000000000000000002000000000000006400000000000000000000000000000000000000000000000000000000000000d20400000000000000000000000000000000000000000000000000000000000050c3000000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d5000000c800000000000000000000000000000000000000000000000000000000000000d500000001549a51956bd364d8bb2efb1f1ea4436e8d7764ff015a6aa788d53d27bf35bafc1c45ff8734767eeeea3c334eacd3b759090f7937813e3a0cbc3a233eee92ccba94c8d76aa68c8a23257a81fa9aac7d0eabf89bb6ea484955196fc9a0ab07522ca3d50ab361f1628061be533586f64f50678a793e64a207a5df408217ed91c94f3c6f6100bf6e2f6ff982b7ac3f300face1b52ae3fc68ee030fdc3150d73a056bd4df66001059c6d1cb08ea2b39d0d49b0efaa75b8b61fb7f2b9caca6896aea156ed030004701796c517e2b010e387fefc702dabc6b4d2c732a173d33e0c272701e4f860068bad6020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" @@ -36,7 +36,7 @@ "GasLimit": 70000, "GasPrice": "999", "PriorityGasPrice": "10", - "MaxFeePerDataGas": "20", + "MaxFeePerBlobGas": "20", "Data": "0xa9fc4e91a83d0307d0aa69047208b24e15bd81098f9f580176ddf17604604b9259ddb3477cd87b6fd26d00615d65bb7e09597c1ea058e700a3da71696887edc6c0383f63e6a51b313afcf46f7159649cd4da51903c820aa577e93adc54cb62bd05a5d1bc8f9b4bcbf8de9670040106859f3c78b5f4d0e69804e743b905506f23503f720744f6a7e5ade176064fdc43803dcd6a12eda8d523fea35c4fe7e9537fa48f87c7b23f9f01e7ba0aa4f6688dbdb2646ec62d0156a1529121c702d00c73f27add8d238d04248a2c5b76e4b108116b2f9699523521586464b86dd4d6048c35719131dc4828ab8c95cb2aeb29fde8163f10994bfcffaf041250da0f2525a8" }, "RawEncodedTransaction": "0x033c00000076010000a6010000b9f0f8d300dd1026eaae3514ec7c5256da8d5cab3c2dad5de17b1d313d090d4a8e3c16a5a18958689c5bfc8d796469b2450000000022914d549bf0a6e1768dd8bd194398b90d3ff9e106e2eaf49ea4b6c3393bdc4e3095de1696ff03c6411f4253caaf8a67ddc6960621c62427c5175cbc4b54ba62330500000000000000000000000000000000000000000000000000000000000003000000000000000a00000000000000000000000000000000000000000000000000000000000000e7030000000000000000000000000000000000000000000000000000000000007011010000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000001400000000000000000000000000000000000000000000000000000000000000d500000001a39c4e1b259473fbcc5213a0613eb53a8c50bf7601993d186e446474c02a7128f7664b21f84cf71bf23c094891c7a0eb50d60aac82fe74ca635e5232c171eb8389f4b572b5da6e6b0f1f352a6e3baa9730f255991994a6df1604fcb4a6b08b125e6de7c4a9fc4e91a83d0307d0aa69047208b24e15bd81098f9f580176ddf17604604b009259ddb3477cd87b6fd26d00615d65bb7e09597c1ea058e700a3da7169688700edc6c0383f63e6a51b313afcf46f7159649cd4da51903c820aa577e93adc5400cb62bd05a5d1bc8f9b4bcbf8de9670040106859f3c78b5f4d0e69804e743b90005506f23503f720744f6a7e5ade176064fdc43803dcd6a12eda8d523fea35c004fe7e9537fa48f87c7b23f9f01e7ba0aa4f6688dbdb2646ec62d0156a152910021c702d00c73f27add8d238d04248a2c5b76e4b108116b2f969952352158640064b86dd4d6048c35719131dc4828ab8c95cb2aeb29fde8163f10994bfcffaf00041250da0f2525a80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" @@ -50,7 +50,7 @@ "GasLimit": 21000, "GasPrice": "1001", "PriorityGasPrice": "35", - "MaxFeePerDataGas": "70", + "MaxFeePerBlobGas": "70", "Data": "0xab7df14deb748629d5977f83d8536dc5c24561b1cea925451174062650693e3a0a4e9b888a2b0851c37b9ba08d4ed87ec3f877b9e61579a406b5254151b5dc19367820e899c7044be963af47e6f48d3dd2c6641176a1a6f2c29de718ad4d5ef81d8dea813f6570525d1eb9b41f2c4a957fb2af932fbdd8b46fc8086a705b8ce89b319000d5820a8e03e009f0068901762602836f8275208df4061ec3af8c890dcee5b75606084179b671e58e7664ccb115f5986291bdae081600ca52c4d68b81998ed228a7eed85bdcf421f779495ee4a5ceb8f640ba736f2528a4c59dac9d7772088681ecdcf80127d983cfe504281f4c13a2ff04e33dd279b91240ea54804110f59977d0fcf70a0a9b22bbd0d450e90ca09ef09f4400066486a2c87440b378970d888303a25afe22968c07cfa1184a7b9a12143a1953715fe0f939c5d206452ddddeb5f202f4b23a0a372328cb9f508e70c2c6c988d81dd6f7dd811feb6d56baaaf2682e9de965ab0eb31f729b59550f0d01a9f0d89a8df5de74a816ef184d7889fe7447596e4084afa4d6a927d268c1cc4a6b5fa60df8410c8df357e989f724f0d1b8fa4376a7dc701e6dd9426d558f7451d4d3bbba18558fd9ed1354143fe40f47cc5c00c3bf1e9e566afe04d2f6e68811a889888bea0b9c09ea3cf3d869f973faabc894d4b217ba9421eafcdd6d554021a5ef3b471d3d343c7e9096113d32c44f7c164d5399afface623210089d580a6a00050c08b99af5005aad43332661ff482d75777813f922f642132836ba9477477cabff285e65c26ec7ce7d93ef048861e0eeff856a5239c36e574a0436e0c02c79747137e94dacdde8a3d182590110c1666d09b189fadb211bc3bff278bbbab9017cc38a67d9fc3161ed509309a9117e28b36dfc0fc947f12698204c3a461173849f247172d30a344e8f60c875bed85b40f7f48dd1eea5be4e23982097b980eb59349155fe5428f1e09c87052b0d19e2032ba3207b5ae082eb4c9073cd320a65dbde9eb1bc036bc9f8bd2fb98cc3d484f51ffffda4262506548ab031a8b096c7407297c17705b82b99d337777e19002cec4e6eb3a1f59c3cfe34e3c33463c2720580a3ce8837cae469a14855b1cd22998720ac59453ee2f1710e1393c0a373b53e55e4cf662873b98a4665b8a34c2766eb6aebf9d1f66913e661b826382c855d6bcae2604d01d61647084bf72c114ced593104bafc8e79e341b5d79eca3b962422fdc81069e5bc4e1b2278719e4994f449afc12280841a617e6dedcb7ed13392738417c7991a12984abf2af764ca8a5a2e06ed2082c7523d1a00ffbb8722e2792dacc3b8810f85ccd7bcee288ed42be6a9e13a14c0accc9dc3bb7f984612d7a16397ba12e046f4e8e39914aa83de3da1a32cd6df36a290074de4cf67165c9055454b320146023400c3f5bc2946" }, "RawEncodedTransaction": "0x033c00000076010000a60100008688d5a22dfcbac7ba4554a408e4cd987e899ac34ac328647894b90715efd9691b48177f9f18d8296286e675197af3ef4500000001dc17eaa54e29b2def5c88ec0cd9c223e1983abee1f9f3a6da927e5aa59a8a9fb082b03a9b38cfae8007625d9ae04da8945359ecc8ab6b9b175041b1c7abbc34c330500000000000000000000000000000000000000000000000000000000000004000000000000002300000000000000000000000000000000000000000000000000000000000000e9030000000000000000000000000000000000000000000000000000000000000852000000000000c00000000100000000000000000000000000000000000000000000000000000000000000d5000000d50000004600000000000000000000000000000000000000000000000000000000000000d500000001d59399657a78bb69dee83c416c13be711e02fa2301bac1ab118201c78f5372db0b0d587a9b4f198c83b5a7c52cc8f76bb0081892b8034bc918ce25dfe12bc4109e7576a01bb5e0f1bc9503d647d750a9451ff02007fbe7533e95d02cdc495361e7e0a25eab7df14deb748629d5977f83d8536dc5c24561b1cea925451174062650693e003a0a4e9b888a2b0851c37b9ba08d4ed87ec3f877b9e61579a406b5254151b500dc19367820e899c7044be963af47e6f48d3dd2c6641176a1a6f2c29de718ad004d5ef81d8dea813f6570525d1eb9b41f2c4a957fb2af932fbdd8b46fc8086a00705b8ce89b319000d5820a8e03e009f0068901762602836f8275208df4061e00c3af8c890dcee5b75606084179b671e58e7664ccb115f5986291bdae08160000ca52c4d68b81998ed228a7eed85bdcf421f779495ee4a5ceb8f640ba736f250028a4c59dac9d7772088681ecdcf80127d983cfe504281f4c13a2ff04e33dd20079b91240ea54804110f59977d0fcf70a0a9b22bbd0d450e90ca09ef09f440000066486a2c87440b378970d888303a25afe22968c07cfa1184a7b9a12143a190053715fe0f939c5d206452ddddeb5f202f4b23a0a372328cb9f508e70c2c6c90088d81dd6f7dd811feb6d56baaaf2682e9de965ab0eb31f729b59550f0d01a900f0d89a8df5de74a816ef184d7889fe7447596e4084afa4d6a927d268c1cc4a006b5fa60df8410c8df357e989f724f0d1b8fa4376a7dc701e6dd9426d558f740051d4d3bbba18558fd9ed1354143fe40f47cc5c00c3bf1e9e566afe04d2f6e6008811a889888bea0b9c09ea3cf3d869f973faabc894d4b217ba9421eafcdd6d00554021a5ef3b471d3d343c7e9096113d32c44f7c164d5399afface62321008009d580a6a00050c08b99af5005aad43332661ff482d75777813f922f64213280036ba9477477cabff285e65c26ec7ce7d93ef048861e0eeff856a5239c36e57004a0436e0c02c79747137e94dacdde8a3d182590110c1666d09b189fadb211b00c3bff278bbbab9017cc38a67d9fc3161ed509309a9117e28b36dfc0fc947f1002698204c3a461173849f247172d30a344e8f60c875bed85b40f7f48dd1eea500be4e23982097b980eb59349155fe5428f1e09c87052b0d19e2032ba3207b5a00e082eb4c9073cd320a65dbde9eb1bc036bc9f8bd2fb98cc3d484f51ffffda400262506548ab031a8b096c7407297c17705b82b99d337777e19002cec4e6eb300a1f59c3cfe34e3c33463c2720580a3ce8837cae469a14855b1cd22998720ac0059453ee2f1710e1393c0a373b53e55e4cf662873b98a4665b8a34c2766eb6a00ebf9d1f66913e661b826382c855d6bcae2604d01d61647084bf72c114ced59003104bafc8e79e341b5d79eca3b962422fdc81069e5bc4e1b2278719e4994f40049afc12280841a617e6dedcb7ed13392738417c7991a12984abf2af764ca8a005a2e06ed2082c7523d1a00ffbb8722e2792dacc3b8810f85ccd7bcee288ed4002be6a9e13a14c0accc9dc3bb7f984612d7a16397ba12e046f4e8e39914aa8300de3da1a32cd6df36a290074de4cf67165c9055454b320146023400c3f5bc29004600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 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 406e5950401..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 @@ -84,8 +84,8 @@ public static BlockHeader prepareWrongParentHash(final BlockHeader blockHeader) blockHeader.getMixHash(), blockHeader.getNonce(), blockHeader.getWithdrawalsRoot().orElse(null), - blockHeader.getDataGasUsed().orElse(null), - blockHeader.getExcessDataGas().orElse(null), + blockHeader.getBlobGasUsed().orElse(null), + blockHeader.getExcessBlobGas().orElse(null), blockHeader.getDepositsRoot().orElse(null), new MainnetBlockHeaderFunctions()); } 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 f31afc52053..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 @@ -21,7 +21,7 @@ import static org.hyperledger.besu.evmtool.StateTestSubCommand.COMMAND_NAME; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -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; @@ -237,8 +237,8 @@ private void traceTestSpecs(final String test, final List extractTransactions( builder.maxFeePerGas(Wei.fromHexString(txNode.get("maxFeePerGas").textValue())); } if (txNode.has("maxFeePerBlobGas")) { - builder.maxFeePerDataGas( + builder.maxFeePerBlobGas( Wei.fromHexString(txNode.get("maxFeePerBlobGas").textValue())); } @@ -254,7 +254,7 @@ static T8nResult runTest( final Wei blobGasPrice = protocolSpec .getFeeMarket() - .dataPricePerGas(blockHeader.getExcessDataGas().orElse(DataGas.ZERO)); + .blobGasPricePerGas(blockHeader.getExcessBlobGas().orElse(BlobGas.ZERO)); List receipts = new ArrayList<>(); List invalidTransactions = new ArrayList<>(rejections); @@ -404,15 +404,15 @@ static T8nResult runTest( .getWithdrawalsRoot() .ifPresent(wr -> resultObject.put("withdrawalsRoot", wr.toHexString())); blockHeader - .getDataGasUsed() + .getBlobGasUsed() .ifPresentOrElse( bgu -> resultObject.put("blobGasUsed", Bytes.ofUnsignedLong(bgu).toQuantityHexString()), () -> blockHeader - .getExcessDataGas() + .getExcessBlobGas() .ifPresent(ebg -> resultObject.put("blobGasUsed", "0x0"))); blockHeader - .getExcessDataGas() + .getExcessBlobGas() .ifPresent(ebg -> resultObject.put("currentExcessBlobGas", ebg.toShortHexString())); ObjectNode allocObject = objectMapper.createObjectNode(); diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 5f4e3901c56..2be5393103a 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -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 8e5d0156502..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; @@ -166,6 +166,8 @@ public ReferenceTestBlockHeader( @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 @@ -189,8 +191,12 @@ public ReferenceTestBlockHeader( Hash.fromHexString(mixHash), // mixHash Bytes.fromHexStringLenient(nonce).toLong(), withdrawalsRoot != null ? Hash.fromHexString(withdrawalsRoot) : null, - dataGasUsed != null ? Long.decode(dataGasUsed) : 0, - 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 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 cfa73ac82a7..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,7 +19,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -138,7 +138,7 @@ public ReferenceTestEnv( 0L, null, // withdrawalsRoot currentBlobGasUsed == null ? null : Long.decode(currentBlobGasUsed), - currentExcessBlobGas == null ? null : DataGas.fromHexString(currentExcessBlobGas), + currentExcessBlobGas == null ? null : BlobGas.fromHexString(currentExcessBlobGas), null, // depositsRoot new MainnetBlockHeaderFunctions()); this.parentDifficulty = parentDifficulty; @@ -211,12 +211,12 @@ public BlockHeader updateFromParentValues(final ProtocolSpec protocolSpec) { .buildBlockHeader(), null))); } - if (excessDataGas.isEmpty() && parentExcessBlobGas != null && parentBlobGasUsed != null) { - builder.excessDataGas( - DataGas.of( + if (excessBlobGas.isEmpty() && parentExcessBlobGas != null && parentBlobGasUsed != null) { + builder.excessBlobGas( + BlobGas.of( protocolSpec .getGasCalculator() - .computeExcessDataGas( + .computeExcessBlobGas( Long.decode(parentExcessBlobGas), Long.decode(parentGasUsed)))); } 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 e8f171fafe0..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 @@ -72,7 +72,7 @@ public class StateTestVersionedTransaction { private final List values; private final List payloads; private final Optional>> maybeAccessLists; - private final Wei maxFeePerDataGas; + private final Wei maxFeePerBlobGas; private final List blobVersionedHashes; /** @@ -102,7 +102,7 @@ public StateTestVersionedTransaction( @JsonProperty("data") final String[] data, @JsonDeserialize(using = StateTestAccessListDeserializer.class) @JsonProperty("accessLists") final List> maybeAccessLists, - @JsonProperty("maxFeePerDataGas") final String maxFeePerDataGas, + @JsonProperty("maxFeePerBlobGas") final String maxFeePerBlobGas, @JsonProperty("blobVersionedHashes") final List blobVersionedHashes) { this.nonce = Bytes.fromHexStringLenient(nonce).toLong(); @@ -121,8 +121,8 @@ public StateTestVersionedTransaction( this.values = parseArray(value, Wei::fromHexString); this.payloads = parseArray(data, Bytes::fromHexString); this.maybeAccessLists = Optional.ofNullable(maybeAccessLists); - this.maxFeePerDataGas = - Optional.ofNullable(maxFeePerDataGas).map(Wei::fromHexString).orElse(null); + this.maxFeePerBlobGas = + Optional.ofNullable(maxFeePerBlobGas).map(Wei::fromHexString).orElse(null); this.blobVersionedHashes = blobVersionedHashes; } @@ -160,7 +160,7 @@ public Transaction get(final GeneralStateTestCaseSpec.Indexes indexes) { Optional.ofNullable(maxPriorityFeePerGas).ifPresent(transactionBuilder::maxPriorityFeePerGas); maybeAccessLists.ifPresent( accessLists -> transactionBuilder.accessList(accessLists.get(indexes.data))); - Optional.ofNullable(maxFeePerDataGas).ifPresent(transactionBuilder::maxFeePerDataGas); + Optional.ofNullable(maxFeePerBlobGas).ifPresent(transactionBuilder::maxFeePerBlobGas); transactionBuilder.versionedHashes(blobVersionedHashes); transactionBuilder.guessType(); 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 0a975bc941e..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().dataPricePerGas(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/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 1939f107002..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 @@ -21,7 +21,7 @@ * *
      *
    • Gas costs for TSTORE/TLOAD - *
    • Data gas for EIP-4844 + *
    • Blob gas for EIP-4844 *
    */ public class CancunGasCalculator extends ShanghaiGasCalculator { @@ -44,13 +44,13 @@ private CancunGasCalculator(final int maxPrecompile) { private static final long TSTORE_GAS = WARM_STORAGE_READ_COST; /** - * The data gas cost per blob. This is the gas cost for each blob of data that is added to the + * 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 DATA_GAS_PER_BLOB = 1 << 17; + public static final long BLOB_GAS_PER_BLOB = 1 << 17; - /** The target data gas per block. */ - public static final long TARGET_DATA_GAS_PER_BLOCK = 0x60000; + /** The target blob gas per block. */ + public static final long TARGET_BLOB_GAS_PER_BLOCK = 0x60000; // EIP-1153 @Override @@ -64,47 +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 data gas per block. + * Retrieves the target blob gas per block. * - * @return The target data gas per block. + * @return The target blob gas per block. */ - public long getTargetDataGasPerBlock() { - return TARGET_DATA_GAS_PER_BLOCK; + public long getTargetBlobGasPerBlock() { + return TARGET_BLOB_GAS_PER_BLOCK; } /** - * Computes the excess data gas for a given block based on the parent's excess data gas and data - * gas used. If the sum of parent's excess data gas and parent's data gas used is less than the - * target data gas per block, the excess data gas is calculated as 0. Otherwise, it is computed as - * the difference between the sum and the target data 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 parentExcessDataGas The excess data gas of the parent block. - * @param newBlobs data gas incurred by current block - * @return The excess data gas for the current 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 computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { - final long consumedDataGas = dataGasCost(newBlobs); - final long currentExcessDataGas = parentExcessDataGas + consumedDataGas; + public long computeExcessBlobGas(final long parentExcessBlobGas, final int newBlobs) { + final long consumedBlobGas = blobGasCost(newBlobs); + final long currentExcessBlobGas = parentExcessBlobGas + consumedBlobGas; - 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; } @Override - public long computeExcessDataGas(final long parentExcessDataGas, final long dataGasUsed) { - final long currentExcessDataGas = parentExcessDataGas + dataGasUsed; + 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 8f523fb4689..54524825a5c 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 @@ -519,30 +519,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 data gas, given the parent value and the data gas used + * Compute the new value for the excess blob gas, given the parent value and the blob gas used * - * @param parentExcessDataGas excess data gas from the parent - * @param dataGasUsed data gas used - * @return the new excess data gas value + * @param parentExcessBlobGas excess blob gas from the parent + * @param blobGasUsed blob gas used + * @return the new excess blob gas value */ - default long computeExcessDataGas(final long parentExcessDataGas, final long dataGasUsed) { + default long computeExcessBlobGas(final long parentExcessBlobGas, final long blobGasUsed) { return 0L; } } 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 index e0a7edc2a43..f8e53703b25 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java @@ -27,20 +27,20 @@ public class CancunGasCalculatorTest { private final CancunGasCalculator gasCalculator = new CancunGasCalculator(); @ParameterizedTest(name = "{index} - parent gas {0}, used gas {1}, new excess {2}") - @MethodSource("dataGasses") - public void shouldCalculateExcessDataGasCorrectly( + @MethodSource("blobGasses") + public void shouldCalculateExcessBlobGasCorrectly( final long parentExcess, final long used, final long expected) { - assertThat(gasCalculator.computeExcessDataGas(parentExcess, (int) used)).isEqualTo(expected); + assertThat(gasCalculator.computeExcessBlobGas(parentExcess, (int) used)).isEqualTo(expected); } - static Iterable dataGasses() { - long targetGasPerBlock = CancunGasCalculator.TARGET_DATA_GAS_PER_BLOCK; + 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.DATA_GAS_PER_BLOB), + 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/precompile/Benchmarks.java b/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java index 225212ddb8a..e25701d6d0d 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 @@ -275,6 +275,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()); diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index dda81e5e282..a4e4cdb95a9 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -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 = 'kmY3fycbIcbEHpf8aezNlZs3M8dD3lDf74lvedkDDu0=' + knownHash = 'jxYLp4SMEdixHCmHDjylVvl7W8smMCWispBMKPJlFXg=' } check.dependsOn('checkAPIChanges') 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 b06f020ad8b..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,18 +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 data_gas_used of this header. + * The blob_gas_used of this header. * - * @return The data_gas_used of this header. + * @return The blob_gas_used of this header. */ @Unstable - Optional getDataGasUsed(); + Optional getBlobGasUsed(); } From 92a3c5b139bf57d1521c8f8ec623934c50430353 Mon Sep 17 00:00:00 2001 From: George Tebrean <99179176+gtebrean@users.noreply.github.com> Date: Mon, 21 Aug 2023 03:25:38 +0300 Subject: [PATCH 50/51] Issue 5719 - remove Pretty JSON and make it user configurable (#5766) * add --pretty-json-enabled * update changelog Signed-off-by: George Tebrean * Update CLI option name in CHANGELOG.md Signed-off-by: Sally MacFarlane --------- Signed-off-by: George Tebrean Signed-off-by: Sally MacFarlane Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 7 +++++++ besu/src/test/resources/everything_config.toml | 1 + .../api/handlers/JsonRpcObjectExecutor.java | 13 ++++++++----- .../api/jsonrpc/JsonRpcConfiguration.java | 11 +++++++++++ .../filter/EthJsonRpcHttpServiceTest.java | 16 +++++----------- 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13575e7c2b0..5080389666c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### 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) 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 c72a9766920..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,6 +27,7 @@ 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; @@ -779,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 @@ -2443,6 +2449,7 @@ && rpcHttpAuthenticationCredentialsFile() == null jsonRpcConfiguration.setMaxBatchSize(jsonRPCHttpOptionGroup.rpcHttpMaxBatchSize); jsonRpcConfiguration.setMaxRequestContentLength( jsonRPCHttpOptionGroup.rpcHttpMaxRequestContentLength); + jsonRpcConfiguration.setPrettyJsonEnabled(jsonRPCHttpOptionGroup.prettyJsonEnabled); return jsonRpcConfiguration; } 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/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 e1a655657fa..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 @@ -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) @@ -90,9 +90,12 @@ private static HttpResponseStatus status(final JsonRpcResponse response) { }; } - 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); } 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/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 d881c866da7..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 @@ -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(); From 2bced4ebf96b04f5c7bccc3d013a31f1618700e9 Mon Sep 17 00:00:00 2001 From: matkt Date: Mon, 21 Aug 2023 16:12:16 +0200 Subject: [PATCH 51/51] fix snapsync issue with forest (#5776) Fixing an issue during snapsync with forest related to the heal step Signed-off-by: Karim TAAM --- CHANGELOG.md | 1 + ...nsaiSnapshotWorldStateKeyValueStorage.java | 5 + .../BonsaiWorldStateKeyValueStorage.java | 24 ++-- .../keyvalue/WorldStateKeyValueStorage.java | 5 + .../worldstate/WorldStateStorage.java | 9 ++ .../heal/StorageTrieNodeHealingRequest.java | 19 +-- .../StorageTrieNodeHealingRequestTest.java | 113 ++++++++++++++++++ 7 files changed, 153 insertions(+), 23 deletions(-) create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5080389666c..c46edf12c61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - 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 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 2e89e0f791a..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 @@ -95,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) { 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 04c4aefe66d..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 @@ -166,32 +166,24 @@ public Optional getAccountStateTrieNode(final Bytes location, final Bytes } } - /** - * 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 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) { 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/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/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/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(); + } +}