From ec46f3e5e13d0eeeefc5e17941eb863463b6cdeb Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 17:59:17 -0400 Subject: [PATCH 01/55] Start `op-revm` changes --- crates/interpreter/Cargo.toml | 1 + crates/interpreter/src/instructions/opcode.rs | 8 +++ crates/precompile/Cargo.toml | 1 + crates/precompile/src/lib.rs | 2 + crates/primitives/Cargo.toml | 1 + crates/primitives/src/env.rs | 41 +++++++++++++- crates/primitives/src/specification.rs | 25 +++++++++ crates/revm/Cargo.toml | 1 + crates/revm/src/evm.rs | 6 +++ crates/revm/src/evm_impl.rs | 54 ++++++++++++++++++- 10 files changed, 137 insertions(+), 3 deletions(-) diff --git a/crates/interpreter/Cargo.toml b/crates/interpreter/Cargo.toml index aa43614127..6b65f9c453 100644 --- a/crates/interpreter/Cargo.toml +++ b/crates/interpreter/Cargo.toml @@ -59,3 +59,4 @@ arbitrary = [ "dep:proptest-derive", "revm-primitives/arbitrary", ] +optimism = ["revm-primitives/optimism"] diff --git a/crates/interpreter/src/instructions/opcode.rs b/crates/interpreter/src/instructions/opcode.rs index 7c2f80d71e..fd1d059a74 100644 --- a/crates/interpreter/src/instructions/opcode.rs +++ b/crates/interpreter/src/instructions/opcode.rs @@ -924,5 +924,13 @@ pub const fn spec_opcode_gas(spec_id: SpecId) -> &'static [OpInfo; 256] { gas_opcodee!(LATEST, SpecId::LATEST); LATEST } + SpecId::BEDROCK => { + gas_opcodee!(BEDROCK, SpecId::BEDROCK); + BEDROCK + } + SpecId::REGOLITH => { + gas_opcodee!(REGOLITH, SpecId::REGOLITH); + REGOLITH + } } } diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 3224f1b6d1..09090dbcc7 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -31,3 +31,4 @@ default = ["secp256k1"] # Only problem that it has, it fails to build for wasm target on windows and mac as it is c lib. # If you dont require wasm on win/mac, i would recommend its usage. secp256k1 = ["dep:secp256k1"] +optimism = ["revm-primitives/optimism"] diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index cccc2b0958..3cd41ff96d 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -109,6 +109,8 @@ impl SpecId { Self::BERLIN } LATEST => Self::LATEST, + #[cfg(feature = "optimism")] + BEDROCK | REGOLITH => Self::LATEST, } } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index a1fd2be8a7..c0e76bbd21 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -89,3 +89,4 @@ arbitrary = [ "dep:proptest-derive", "bitflags/arbitrary", ] +optimism = [] diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index d9e41ba308..119e4ea0ad 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -45,6 +45,12 @@ pub struct TxEnv { pub chain_id: Option, pub nonce: Option, pub access_list: Vec<(B160, Vec)>, + #[cfg(feature = "optimism")] + pub source_hash: Option, + #[cfg(feature = "optimism")] + pub mint: Option, + #[cfg(feature = "optimism")] + pub is_system_transaction: Option, } #[derive(Clone, Debug)] @@ -122,6 +128,10 @@ pub struct CfgEnv { /// This is useful for testing method calls with zero gas price. #[cfg(feature = "optional_no_base_fee")] pub disable_base_fee: bool, + /// Enables Optimism's execution changes for deposit transactions and fee + /// collection. + #[cfg(feature = "optimism")] + pub optimism: bool, } impl CfgEnv { @@ -174,6 +184,16 @@ impl CfgEnv { pub fn is_block_gas_limit_disabled(&self) -> bool { false } + + #[cfg(feature = "optimism")] + pub fn is_optimism(&self) -> bool { + self.optimism + } + + #[cfg(not(feature = "optimism"))] + pub fn is_optimism(&self) -> bool { + false + } } #[derive(Clone, Default, Debug, Eq, PartialEq)] @@ -205,6 +225,8 @@ impl Default for CfgEnv { disable_gas_refund: false, #[cfg(feature = "optional_no_base_fee")] disable_base_fee: false, + #[cfg(feature = "optimism")] + optimism: false, } } } @@ -236,6 +258,12 @@ impl Default for TxEnv { chain_id: None, nonce: None, access_list: Vec::new(), + #[cfg(feature = "optimism")] + source_hash: None, + #[cfg(feature = "optimism")] + mint: None, + #[cfg(feature = "optimism")] + is_system_transaction: None, } } } @@ -323,7 +351,11 @@ impl Env { /// Validate transaction against state. #[inline] - pub fn validate_tx_against_state(&self, account: &Account) -> Result<(), InvalidTransaction> { + pub fn validate_tx_against_state( + &self, + account: &Account, + #[cfg(feature = "optimism")] is_deposit: bool, + ) -> Result<(), InvalidTransaction> { // EIP-3607: Reject transactions from senders with deployed code // This EIP is introduced after london but there was no collision in past // so we can leave it enabled always @@ -331,6 +363,13 @@ impl Env { return Err(InvalidTransaction::RejectCallerWithCode); } + // On Optimism, deposit transactions do not have verification on the nonce + // nor the balance of the account. + #[cfg(feature = "optimism")] + if is_deposit { + return Ok(()); + } + // Check that the transaction's nonce is correct if let Some(tx) = self.tx.nonce { let state = account.info.nonce; diff --git a/crates/primitives/src/specification.rs b/crates/primitives/src/specification.rs index f173e96cc0..6f04c2b1dd 100644 --- a/crates/primitives/src/specification.rs +++ b/crates/primitives/src/specification.rs @@ -25,6 +25,10 @@ pub enum SpecId { SHANGHAI = 16, CANCUN = 17, LATEST = 18, + #[cfg(feature = "optimism")] + BEDROCK = 128, + #[cfg(feature = "optimism")] + REGOLITH = 129, } impl SpecId { @@ -52,6 +56,10 @@ impl From<&str> for SpecId { "Merge" => SpecId::MERGE, "Shanghai" => SpecId::SHANGHAI, "Cancun" => SpecId::CANCUN, + #[cfg(feature = "optimism")] + "Bedrock" => SpecId::BEDROCK, + #[cfg(feature = "optimism")] + "Regolith" => SpecId::REGOLITH, _ => SpecId::LATEST, } } @@ -69,6 +77,17 @@ pub trait Spec: Sized { #[inline(always)] fn enabled(spec_id: SpecId) -> bool { + // Optimism's Bedrock and Regolith hardforks implement changes on top of the Merge + // hardfork. This function is modified to preserve the original behavior of the + // spec IDs without having to put hardforks past Merge under + // `#[cfg(not(feature = "optimism"))]`. + #[cfg(feature = "optimism")] + if (Self::SPEC_ID == SpecId::BEDROCK || Self::SPEC_ID == SpecId::REGOLITH) + && spec_id > SpecId::MERGE + { + return false; + } + Self::SPEC_ID as u8 >= spec_id as u8 } } @@ -103,3 +122,9 @@ spec!(MERGE, MergeSpec); spec!(SHANGHAI, ShanghaiSpec); spec!(CANCUN, CancunSpec); spec!(LATEST, LatestSpec); + +// Optimism Hardforks +#[cfg(feature = "optimism")] +spec!(BEDROCK, BedrockSpec); +#[cfg(feature = "optimism")] +spec!(REGOLITH, RegolithSpec); diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 41ff5cb49d..deb223ae3e 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -65,6 +65,7 @@ arbitrary = ["revm-interpreter/arbitrary"] # deprecated feature web3db = [] with-serde = [] +optimism = ["revm-interpreter/optimism", "revm-precompile/optimism"] [[example]] name = "fork_ref_transact" diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs index 526b73fb2a..49e2d38af9 100644 --- a/crates/revm/src/evm.rs +++ b/crates/revm/src/evm.rs @@ -239,6 +239,8 @@ pub fn to_precompile_id(spec_id: SpecId) -> revm_precompile::SpecId { | SpecId::SHANGHAI | SpecId::CANCUN | SpecId::LATEST => revm_precompile::SpecId::BERLIN, + #[cfg(feature = "optimism")] + SpecId::BEDROCK | SpecId::REGOLITH => revm_precompile::SpecId::BERLIN, } } @@ -264,5 +266,9 @@ pub fn evm_inner<'a, DB: Database, const INSPECT: bool>( SpecId::SHANGHAI => create_evm!(ShanghaiSpec, db, env, insp), SpecId::CANCUN => create_evm!(CancunSpec, db, env, insp), SpecId::LATEST => create_evm!(LatestSpec, db, env, insp), + #[cfg(feature = "optimism")] + SpecId::BEDROCK => create_evm!(BedrockSpec, db, env, insp), + #[cfg(feature = "optimism")] + SpecId::REGOLITH => create_evm!(RegolithSpec, db, env, insp), } } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index c3da184cf0..f17470e64a 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -94,7 +94,20 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact fn preverify_transaction(&mut self) -> Result<(), EVMError> { let env = self.env(); + #[cfg(feature = "optimism")] + let is_deposit = env.tx.source_hash.is_some(); + env.validate_block_env::()?; + + // If the transaction is a deposit transaction on Optimism, there are no fee fields to check, + // no nonce to check, and no need to check if EOA (L1 already verified it for us) + // Gas is free, but no refunds! + #[cfg(feature = "optimism")] + if !is_deposit { + env.validate_tx::()?; + } + + #[cfg(not(feature = "optimism"))] env.validate_tx::()?; let tx_caller = env.tx.caller; @@ -114,7 +127,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact .load_account(tx_caller, self.data.db) .map_err(EVMError::Database)?; - self.data.env.validate_tx_against_state(caller_account)?; + self.data.env.validate_tx_against_state( + caller_account, + #[cfg(feature = "optimism")] + is_deposit, + )?; Ok(()) } @@ -127,6 +144,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let tx_gas_limit = env.tx.gas_limit; let tx_is_create = env.tx.transact_to.is_create(); let effective_gas_price = env.effective_gas_price(); + #[cfg(feature = "optimism")] + let tx_mint = env.tx.mint; let initial_gas_spend = initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); @@ -143,6 +162,21 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // load acc let journal = &mut self.data.journaled_state; + + // If the transaction is a deposit with a `Some` `mint` value, add the minted value + // in wei to the caller's balance. This should be persisted to the database prior + // to the rest of execution below. + #[cfg(feature = "optimism")] + if let Some(mint) = tx_mint { + journal + .load_account(tx_caller, self.data.db) + .map_err(EVMError::Database)? + .0 + .info + .balance += U256::from(mint); + journal.checkpoint(); + } + let (caller_account, _) = journal .load_account(tx_caller, self.data.db) .map_err(EVMError::Database)?; @@ -304,8 +338,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, effective_gas_price * U256::from(gas.remaining() + gas_refunded), ); + #[cfg(not(feature = "optimism"))] + let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip; + + #[cfg(feature = "optimism")] + let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip + || self.data.env.tx.source_hash.is_some(); + // transfer fee to coinbase/beneficiary. - if !self.data.env.cfg.disable_coinbase_tip { + if !disable_coinbase_tip { // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. let coinbase_gas_price = if SPEC::enabled(LONDON) { effective_gas_price.saturating_sub(basefee) @@ -326,6 +367,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ); } + #[cfg(feature = "optimism")] + if self.data.env.cfg.optimism && self.data.env.tx.source_hash.is_none() { + // If the transaction is not a deposit transaction, fees are paid out + // to both the Base Fee Vault as well as the Sequencer Fee Vault. + // TODO(clabby): Need to load the L1 fee information from the L1 block contract + // and pay out fees to the vaults. + todo!() + } + (gas.spend() - gas_refunded, gas_refunded) } else { // touch coinbase From 66d200d0ccf125f03a2215975f6c995b04473a1f Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 18:46:38 -0400 Subject: [PATCH 02/55] Start fee distribution changes --- Cargo.lock | 1 + crates/revm/Cargo.toml | 2 + crates/revm/src/evm_impl.rs | 60 ++++++++++++++++++---- crates/revm/src/lib.rs | 7 +++ crates/revm/src/optimism.rs | 100 ++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 crates/revm/src/optimism.rs diff --git a/Cargo.lock b/Cargo.lock index ae802d0394..1bdcb2f8a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2215,6 +2215,7 @@ dependencies = [ "futures", "hex", "hex-literal", + "once_cell", "rayon", "revm-interpreter", "revm-precompile", diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index deb223ae3e..b54598dd60 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -15,6 +15,8 @@ revm-interpreter = { path = "../interpreter", version = "1.1.2", default-feature #misc auto_impl = { version = "1.1", default-features = false } +once_cell = "1.18.0" +bytes = "1.4.0" # Optional serde = { version = "1.0", features = ["derive", "rc"], optional = true } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index f17470e64a..577eb06d16 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -19,6 +19,11 @@ use revm_interpreter::gas::initial_tx_gas; use revm_interpreter::MAX_CODE_SIZE; use revm_precompile::{Precompile, Precompiles}; +#[cfg(feature = "optimism")] +use crate::optimism; +#[cfg(feature = "optimism")] +use core::ops::Mul; + pub struct EVMData<'a, DB: Database> { pub env: &'a mut Env, pub journaled_state: JournaledState, @@ -319,7 +324,16 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let effective_gas_price = self.data.env.effective_gas_price(); let basefee = self.data.env.block.basefee; - let gas_refunded = if self.env().cfg.is_gas_refund_disabled() { + let is_gas_refund_disabled = self.data.env.cfg.is_gas_refund_disabled(); + + #[cfg(feature = "optimism")] + let is_deposit = self.data.env.tx.source_hash.is_some(); + + #[cfg(feature = "optimism")] + let is_gas_refund_disabled = + is_gas_refund_disabled && is_deposit && !SPEC::enabled(SpecId::REGOLITH); + + let gas_refunded = if is_gas_refund_disabled { 0 } else { // EIP-3529: Reduction in refunds @@ -338,12 +352,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, effective_gas_price * U256::from(gas.remaining() + gas_refunded), ); - #[cfg(not(feature = "optimism"))] let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip; #[cfg(feature = "optimism")] - let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip - || self.data.env.tx.source_hash.is_some(); + let disable_coinbase_tip = disable_coinbase_tip || is_deposit; // transfer fee to coinbase/beneficiary. if !disable_coinbase_tip { @@ -368,12 +380,42 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } #[cfg(feature = "optimism")] - if self.data.env.cfg.optimism && self.data.env.tx.source_hash.is_none() { + if self.data.env.cfg.optimism && !is_deposit { // If the transaction is not a deposit transaction, fees are paid out - // to both the Base Fee Vault as well as the Sequencer Fee Vault. - // TODO(clabby): Need to load the L1 fee information from the L1 block contract - // and pay out fees to the vaults. - todo!() + // to both the Base Fee Vault as well as the L1 Fee Vault. + + // Fetch the L1 block information from account storage. + let Ok(l1_block_info) = optimism::fetch_l1_block_info(&mut self.data.db) else { + panic!("Failed to fetch L1 block info from account storage."); + }; + + // Calculate the L1 cost of the transaction based on the L1 block info. + // TODO(clabby): This is incorrect. The L1 cost is computed with the full + // enveloped encoding of the transaction, not its input. How do we get the full + // encoded tx here? We may pass it through the `TxEnv`, but that feels hacky. + let l1_cost = + l1_block_info.calculate_tx_l1_cost::(&self.data.env.tx.data, true); + + // Send the L1 cost of the transaction to the L1 Fee Vault. + let Ok((l1_fee_vault_account, _)) = self + .data + .journaled_state + .load_account(*optimism::L1_FEE_RECIPIENT, self.data.db) + else { + panic!("L1 Fee Vault account not found"); + }; + l1_fee_vault_account.info.balance += l1_cost; + + // Send the base fee of the transaction to the Base Fee Vault. + let Ok((base_fee_vault_account, _)) = self + .data + .journaled_state + .load_account(*optimism::BASE_FEE_RECIPIENT, self.data.db) + else { + panic!("Base Fee Vault account not found"); + }; + base_fee_vault_account.info.balance += + l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); } (gas.spend() - gas_refunded, gas_refunded) diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 0e8ba11c2d..8862ea993a 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -10,6 +10,9 @@ mod evm_impl; mod inspector; mod journaled_state; +#[cfg(feature = "optimism")] +pub mod optimism; + #[cfg(all(feature = "with-serde", not(feature = "serde")))] compile_error!("`with-serde` feature has been renamed to `serde`."); @@ -39,3 +42,7 @@ pub use revm_interpreter::primitives; // reexport inspector implementations pub use inspector::inspectors; pub use inspector::Inspector; + +// export Optimism types, helpers, and constants +#[cfg(feature = "optimism")] +pub use optimism::*; diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs new file mode 100644 index 0000000000..5bbdc1c5e7 --- /dev/null +++ b/crates/revm/src/optimism.rs @@ -0,0 +1,100 @@ +//! Optimism-specific constants, types, and helpers. + +use core::ops::Mul; + +use bytes::Bytes; +use once_cell::sync::Lazy; +use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, Spec, SpecId, U256}; + +const ZERO_BYTE_COST: u64 = 4; +const NON_ZERO_BYTE_COST: u64 = 16; + +static L1_BASE_FEE_SLOT: Lazy = Lazy::new(|| U256::from(1)); +static L1_OVERHEAD_SLOT: Lazy = Lazy::new(|| U256::from(5)); +static L1_SCALAR_SLOT: Lazy = Lazy::new(|| U256::from(6)); + +/// The address of L1 fee recipient. +pub static L1_FEE_RECIPIENT: Lazy
= + Lazy::new(|| Address::from_slice(&hex!("420000000000000000000000000000000000001A"))); + +/// The address of the base fee recipient. +pub static BASE_FEE_RECIPIENT: Lazy
= + Lazy::new(|| Address::from_slice(&hex!("4200000000000000000000000000000000000019"))); + +/// The address of the L1Block contract. +pub static L1_BLOCK_CONTRACT: Lazy
= + Lazy::new(|| Address::from_slice(&hex!("4200000000000000000000000000000000000015"))); + +/// L1 block info +/// +/// We can extract L1 epoch data from each L2 block, by looking at the `setL1BlockValues` +/// transaction data. This data is then used to calculate the L1 cost of a transaction. +/// +/// Here is the format of the `setL1BlockValues` transaction data: +/// +/// setL1BlockValues(uint64 _number, uint64 _timestamp, uint256 _basefee, bytes32 _hash, +/// uint64 _sequenceNumber, bytes32 _batcherHash, uint256 _l1FeeOverhead, uint256 _l1FeeScalar) +/// +/// For now, we only care about the fields necessary for L1 cost calculation. +#[derive(Clone, Debug)] +pub struct L1BlockInfo { + /// The base fee of the L1 origin block. + pub l1_base_fee: U256, + /// The current L1 fee overhead. + pub l1_fee_overhead: U256, + /// The current L1 fee scalar. + pub l1_fee_scalar: U256, +} + +impl L1BlockInfo { + /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero + /// byte and 4 gas per zero byte. + /// + /// Prior to regolith, an extra 68 non-zero bytes were included in the rollup data costs to + /// account for the empty signature. + pub fn data_gas(&self, input: &Bytes) -> U256 { + let mut rollup_data_gas_cost = U256::from(input.iter().fold(0, |acc, byte| { + acc + if *byte == 0x00 { + ZERO_BYTE_COST + } else { + NON_ZERO_BYTE_COST + } + })); + + // Prior to regolith, an extra 68 non zero bytes were included in the rollup data costs. + if !SPEC::enabled(SpecId::REGOLITH) { + rollup_data_gas_cost += U256::from(NON_ZERO_BYTE_COST).mul(U256::from(68)); + } + + rollup_data_gas_cost + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2 + pub fn calculate_tx_l1_cost(&self, input: &Bytes, is_deposit: bool) -> U256 { + let rollup_data_gas_cost = self.data_gas::(input); + + if is_deposit || rollup_data_gas_cost == U256::ZERO { + return U256::ZERO; + } + + rollup_data_gas_cost + .saturating_add(self.l1_fee_overhead) + .saturating_mul(self.l1_base_fee) + .saturating_mul(self.l1_fee_scalar) + .checked_div(U256::from(1_000_000)) + .unwrap_or_default() + } +} + +/// Fetches the L1 block info from the `L1Block` contract in the database. +pub fn fetch_l1_block_info(db: &mut DB) -> Result { + let l1_base_fee = db.storage(*L1_BLOCK_CONTRACT, *L1_BASE_FEE_SLOT)?; + let l1_fee_overhead = db.storage(*L1_BLOCK_CONTRACT, *L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(*L1_BLOCK_CONTRACT, *L1_SCALAR_SLOT)?; + + Ok(L1BlockInfo { + l1_base_fee, + l1_fee_overhead, + l1_fee_scalar, + }) +} From c61c7624e70908c3b866be3b66d9af9e4c894502 Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 19:15:28 -0400 Subject: [PATCH 03/55] Add L1 fee deduction --- crates/interpreter/src/instructions/opcode.rs | 2 + crates/primitives/src/result.rs | 2 + crates/revm/src/evm_impl.rs | 62 +++++++++++++++---- crates/revm/src/optimism.rs | 3 +- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/crates/interpreter/src/instructions/opcode.rs b/crates/interpreter/src/instructions/opcode.rs index fd1d059a74..ab042cbd4e 100644 --- a/crates/interpreter/src/instructions/opcode.rs +++ b/crates/interpreter/src/instructions/opcode.rs @@ -924,10 +924,12 @@ pub const fn spec_opcode_gas(spec_id: SpecId) -> &'static [OpInfo; 256] { gas_opcodee!(LATEST, SpecId::LATEST); LATEST } + #[cfg(feature = "optimism")] SpecId::BEDROCK => { gas_opcodee!(BEDROCK, SpecId::BEDROCK); BEDROCK } + #[cfg(feature = "optimism")] SpecId::REGOLITH => { gas_opcodee!(REGOLITH, SpecId::REGOLITH); REGOLITH diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs index d5a59aaaed..4549b09560 100644 --- a/crates/primitives/src/result.rs +++ b/crates/primitives/src/result.rs @@ -183,6 +183,8 @@ pub enum InvalidTransaction { /// Access list is not supported is not supported /// for blocks before Berlin hardfork. AccessListNotSupported, + #[cfg(feature = "optimism")] + DepositSystemTxPostRegolith, } /// When transaction return successfully without halts. diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 577eb06d16..dd612c4213 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -108,8 +108,18 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // no nonce to check, and no need to check if EOA (L1 already verified it for us) // Gas is free, but no refunds! #[cfg(feature = "optimism")] - if !is_deposit { - env.validate_tx::()?; + { + if !is_deposit { + env.validate_tx::()?; + } + + // Do not allow for a system transaction to be processed if Regolith is enabled. + if is_deposit + && env.tx.is_system_transaction.unwrap_or(false) + && GSPEC::enabled(SpecId::REGOLITH) + { + return Err(InvalidTransaction::DepositSystemTxPostRegolith.into()); + } } #[cfg(not(feature = "optimism"))] @@ -168,18 +178,39 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // load acc let journal = &mut self.data.journaled_state; - // If the transaction is a deposit with a `Some` `mint` value, add the minted value - // in wei to the caller's balance. This should be persisted to the database prior - // to the rest of execution below. #[cfg(feature = "optimism")] - if let Some(mint) = tx_mint { - journal - .load_account(tx_caller, self.data.db) - .map_err(EVMError::Database)? - .0 - .info - .balance += U256::from(mint); - journal.checkpoint(); + if self.data.env.cfg.optimism { + // If the transaction is a deposit with a `Some` `mint` value, add the minted value + // in wei to the caller's balance. This should be persisted to the database prior + // to the rest of execution below. + if let Some(mint) = tx_mint { + journal + .load_account(tx_caller, self.data.db) + .map_err(EVMError::Database)? + .0 + .info + .balance += U256::from(mint); + journal.checkpoint(); + } + + // If the transaction is not a deposit transaction, subtract the L1 data fee from the + // caller's balance directly after minting the requested amount of ETH. + #[cfg(feature = "optimism")] + if let Ok(l1_block_info) = optimism::fetch_l1_block_info(&mut self.data.db) { + if !self.data.env.tx.source_hash.is_some() { + // TODO(clabby): This is incorrect. The L1 cost is computed with the full + // enveloped encoding of the transaction, not its input. + let l1_cost = U256::from( + l1_block_info.calculate_tx_l1_cost::(&self.data.env.tx.data, false), + ); + journal + .load_account(tx_caller, self.data.db) + .map_err(EVMError::Database)? + .0 + .info + .balance -= l1_cost; + } + } } let (caller_account, _) = journal @@ -329,6 +360,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, #[cfg(feature = "optimism")] let is_deposit = self.data.env.tx.source_hash.is_some(); + // Prior to Regolith, deposit transactions did not receive gas refunds. #[cfg(feature = "optimism")] let is_gas_refund_disabled = is_gas_refund_disabled && is_deposit && !SPEC::enabled(SpecId::REGOLITH); @@ -354,6 +386,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip; + // All deposit transactions skip the coinbase tip in favor of paying the + // various fee vaults. #[cfg(feature = "optimism")] let disable_coinbase_tip = disable_coinbase_tip || is_deposit; @@ -404,6 +438,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, else { panic!("L1 Fee Vault account not found"); }; + l1_fee_vault_account.mark_touch(); l1_fee_vault_account.info.balance += l1_cost; // Send the base fee of the transaction to the Base Fee Vault. @@ -414,6 +449,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, else { panic!("Base Fee Vault account not found"); }; + base_fee_vault_account.mark_touch(); base_fee_vault_account.info.balance += l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); } diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 5bbdc1c5e7..62b157d5f6 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -1,8 +1,7 @@ //! Optimism-specific constants, types, and helpers. -use core::ops::Mul; - use bytes::Bytes; +use core::ops::Mul; use once_cell::sync::Lazy; use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, Spec, SpecId, U256}; From 2257bb94d1fa4e4a2c562a5ac18c7277f835ac38 Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 19:41:05 -0400 Subject: [PATCH 04/55] Start deposit tx gas accounting --- crates/revm/src/evm_impl.rs | 56 +++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index dd612c4213..35eee40ef4 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -161,6 +161,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] let tx_mint = env.tx.mint; + #[cfg(feature = "optimism")] + let tx_system = env.tx.is_system_transaction; + #[cfg(feature = "optimism")] + let is_deposit = env.tx.source_hash.is_some(); let initial_gas_spend = initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); @@ -197,7 +201,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // caller's balance directly after minting the requested amount of ETH. #[cfg(feature = "optimism")] if let Ok(l1_block_info) = optimism::fetch_l1_block_info(&mut self.data.db) { - if !self.data.env.tx.source_hash.is_some() { + if !is_deposit { // TODO(clabby): This is incorrect. The L1 cost is computed with the full // enveloped encoding of the transaction, not its input. let l1_cost = U256::from( @@ -277,11 +281,57 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact if crate::USE_GAS { match exit_reason { return_ok!() => { - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); + #[cfg(not(feature = "optimism"))] + { + gas.erase_cost(ret_gas.remaining()); + gas.record_refund(ret_gas.refunded()); + } + + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + #[cfg(feature = "optimism")] + if !is_deposit || GSPEC::enabled(SpecId::REGOLITH) { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(ret_gas.remaining()); + gas.record_refund(ret_gas.refunded()); + } else if is_deposit && tx_system.unwrap_or(false) { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(tx_gas_limit); + } } return_revert!() => { + #[cfg(not(feature = "optimism"))] gas.erase_cost(ret_gas.remaining()); + + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + #[cfg(feature = "optimism")] + if !is_deposit || GSPEC::enabled(SpecId::REGOLITH) { + gas.erase_cost(ret_gas.remaining()); + } } _ => {} } From 3fd2f613312b06513ccc132203763482c650015c Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 20:10:08 -0400 Subject: [PATCH 05/55] Move L1 cost into `TxEnv` --- crates/primitives/src/env.rs | 4 + crates/revm/src/evm_impl.rs | 184 +++++++++++++++++------------------ crates/revm/src/optimism.rs | 67 +++---------- 3 files changed, 104 insertions(+), 151 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 119e4ea0ad..9f21cd6498 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -51,6 +51,8 @@ pub struct TxEnv { pub mint: Option, #[cfg(feature = "optimism")] pub is_system_transaction: Option, + #[cfg(feature = "optimism")] + pub l1_cost: Option, } #[derive(Clone, Debug)] @@ -264,6 +266,8 @@ impl Default for TxEnv { mint: None, #[cfg(feature = "optimism")] is_system_transaction: None, + #[cfg(feature = "optimism")] + l1_cost: None, } } } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 35eee40ef4..975815507a 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -164,6 +164,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact #[cfg(feature = "optimism")] let tx_system = env.tx.is_system_transaction; #[cfg(feature = "optimism")] + let tx_l1_cost = env.tx.l1_cost; + #[cfg(feature = "optimism")] let is_deposit = env.tx.source_hash.is_some(); let initial_gas_spend = @@ -200,13 +202,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // If the transaction is not a deposit transaction, subtract the L1 data fee from the // caller's balance directly after minting the requested amount of ETH. #[cfg(feature = "optimism")] - if let Ok(l1_block_info) = optimism::fetch_l1_block_info(&mut self.data.db) { - if !is_deposit { - // TODO(clabby): This is incorrect. The L1 cost is computed with the full - // enveloped encoding of the transaction, not its input. - let l1_cost = U256::from( - l1_block_info.calculate_tx_l1_cost::(&self.data.env.tx.data, false), - ); + if !is_deposit { + if let Some(l1_cost) = tx_l1_cost { journal .load_account(tx_caller, self.data.db) .map_err(EVMError::Database)? @@ -400,120 +397,115 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, fn finalize(&mut self, gas: &Gas) -> (HashMap, Vec, u64, u64) { let caller = self.data.env.tx.caller; let coinbase = self.data.env.block.coinbase; - let (gas_used, gas_refunded) = - if crate::USE_GAS { - let effective_gas_price = self.data.env.effective_gas_price(); - let basefee = self.data.env.block.basefee; - - let is_gas_refund_disabled = self.data.env.cfg.is_gas_refund_disabled(); + let (gas_used, gas_refunded) = if crate::USE_GAS { + let effective_gas_price = self.data.env.effective_gas_price(); + let basefee = self.data.env.block.basefee; - #[cfg(feature = "optimism")] - let is_deposit = self.data.env.tx.source_hash.is_some(); + let is_gas_refund_disabled = self.data.env.cfg.is_gas_refund_disabled(); - // Prior to Regolith, deposit transactions did not receive gas refunds. - #[cfg(feature = "optimism")] - let is_gas_refund_disabled = - is_gas_refund_disabled && is_deposit && !SPEC::enabled(SpecId::REGOLITH); + #[cfg(feature = "optimism")] + let is_deposit = self.data.env.tx.source_hash.is_some(); - let gas_refunded = if is_gas_refund_disabled { - 0 - } else { - // EIP-3529: Reduction in refunds - let max_refund_quotient = if SPEC::enabled(LONDON) { 5 } else { 2 }; - min(gas.refunded() as u64, gas.spend() / max_refund_quotient) - }; + // Prior to Regolith, deposit transactions did not receive gas refunds. + #[cfg(feature = "optimism")] + let is_gas_refund_disabled = + is_gas_refund_disabled && is_deposit && !SPEC::enabled(SpecId::REGOLITH); - // return balance of not spend gas. - let Ok((caller_account, _)) = - self.data.journaled_state.load_account(caller, self.data.db) - else { - panic!("caller account not found"); - }; + let gas_refunded = if is_gas_refund_disabled { + 0 + } else { + // EIP-3529: Reduction in refunds + let max_refund_quotient = if SPEC::enabled(LONDON) { 5 } else { 2 }; + min(gas.refunded() as u64, gas.spend() / max_refund_quotient) + }; - caller_account.info.balance = caller_account.info.balance.saturating_add( - effective_gas_price * U256::from(gas.remaining() + gas_refunded), - ); + // return balance of not spend gas. + let Ok((caller_account, _)) = + self.data.journaled_state.load_account(caller, self.data.db) + else { + panic!("caller account not found"); + }; - let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip; + caller_account.info.balance = caller_account + .info + .balance + .saturating_add(effective_gas_price * U256::from(gas.remaining() + gas_refunded)); - // All deposit transactions skip the coinbase tip in favor of paying the - // various fee vaults. - #[cfg(feature = "optimism")] - let disable_coinbase_tip = disable_coinbase_tip || is_deposit; + let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip; - // transfer fee to coinbase/beneficiary. - if !disable_coinbase_tip { - // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. - let coinbase_gas_price = if SPEC::enabled(LONDON) { - effective_gas_price.saturating_sub(basefee) - } else { - effective_gas_price - }; + // All deposit transactions skip the coinbase tip in favor of paying the + // various fee vaults. + #[cfg(feature = "optimism")] + let disable_coinbase_tip = disable_coinbase_tip || is_deposit; - let Ok((coinbase_account, _)) = self - .data - .journaled_state - .load_account(coinbase, self.data.db) - else { - panic!("coinbase account not found"); - }; - coinbase_account.mark_touch(); - coinbase_account.info.balance = coinbase_account.info.balance.saturating_add( - coinbase_gas_price * U256::from(gas.spend() - gas_refunded), - ); - } + // transfer fee to coinbase/beneficiary. + if !disable_coinbase_tip { + // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. + let coinbase_gas_price = if SPEC::enabled(LONDON) { + effective_gas_price.saturating_sub(basefee) + } else { + effective_gas_price + }; - #[cfg(feature = "optimism")] - if self.data.env.cfg.optimism && !is_deposit { - // If the transaction is not a deposit transaction, fees are paid out - // to both the Base Fee Vault as well as the L1 Fee Vault. + let Ok((coinbase_account, _)) = self + .data + .journaled_state + .load_account(coinbase, self.data.db) + else { + panic!("coinbase account not found"); + }; + coinbase_account.mark_touch(); + coinbase_account.info.balance = coinbase_account + .info + .balance + .saturating_add(coinbase_gas_price * U256::from(gas.spend() - gas_refunded)); + } - // Fetch the L1 block information from account storage. - let Ok(l1_block_info) = optimism::fetch_l1_block_info(&mut self.data.db) else { - panic!("Failed to fetch L1 block info from account storage."); - }; + #[cfg(feature = "optimism")] + if self.data.env.cfg.optimism && !is_deposit { + // If the transaction is not a deposit transaction, fees are paid out + // to both the Base Fee Vault as well as the L1 Fee Vault. - // Calculate the L1 cost of the transaction based on the L1 block info. - // TODO(clabby): This is incorrect. The L1 cost is computed with the full - // enveloped encoding of the transaction, not its input. How do we get the full - // encoded tx here? We may pass it through the `TxEnv`, but that feels hacky. - let l1_cost = - l1_block_info.calculate_tx_l1_cost::(&self.data.env.tx.data, true); + let Ok(l1_block_info) = optimism::L1BlockInfo::try_fetch(&mut self.data.db) else { + panic!("[OPTIMISM] Failed to load L1 block information."); + }; - // Send the L1 cost of the transaction to the L1 Fee Vault. + // Send the L1 cost of the transaction to the L1 Fee Vault. + if let Some(l1_cost) = self.data.env.tx.l1_cost { let Ok((l1_fee_vault_account, _)) = self .data .journaled_state .load_account(*optimism::L1_FEE_RECIPIENT, self.data.db) else { - panic!("L1 Fee Vault account not found"); + panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); }; l1_fee_vault_account.mark_touch(); l1_fee_vault_account.info.balance += l1_cost; - - // Send the base fee of the transaction to the Base Fee Vault. - let Ok((base_fee_vault_account, _)) = self - .data - .journaled_state - .load_account(*optimism::BASE_FEE_RECIPIENT, self.data.db) - else { - panic!("Base Fee Vault account not found"); - }; - base_fee_vault_account.mark_touch(); - base_fee_vault_account.info.balance += - l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); } - (gas.spend() - gas_refunded, gas_refunded) - } else { - // touch coinbase - let _ = self + // Send the base fee of the transaction to the Base Fee Vault. + let Ok((base_fee_vault_account, _)) = self .data .journaled_state - .load_account(coinbase, self.data.db); - self.data.journaled_state.touch(&coinbase); - (0, 0) - }; + .load_account(*optimism::BASE_FEE_RECIPIENT, self.data.db) + else { + panic!("[OPTIMISM] Failed to load Base Fee Vault account"); + }; + base_fee_vault_account.mark_touch(); + base_fee_vault_account.info.balance += + l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); + } + + (gas.spend() - gas_refunded, gas_refunded) + } else { + // touch coinbase + let _ = self + .data + .journaled_state + .load_account(coinbase, self.data.db); + self.data.journaled_state.touch(&coinbase); + (0, 0) + }; let (new_state, logs) = self.data.journaled_state.finalize(); (new_state, logs, gas_used, gas_refunded) } diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 62b157d5f6..5e0a830b13 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -1,12 +1,7 @@ //! Optimism-specific constants, types, and helpers. -use bytes::Bytes; -use core::ops::Mul; use once_cell::sync::Lazy; -use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, Spec, SpecId, U256}; - -const ZERO_BYTE_COST: u64 = 4; -const NON_ZERO_BYTE_COST: u64 = 16; +use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, U256}; static L1_BASE_FEE_SLOT: Lazy = Lazy::new(|| U256::from(1)); static L1_OVERHEAD_SLOT: Lazy = Lazy::new(|| U256::from(5)); @@ -46,54 +41,16 @@ pub struct L1BlockInfo { } impl L1BlockInfo { - /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero - /// byte and 4 gas per zero byte. - /// - /// Prior to regolith, an extra 68 non-zero bytes were included in the rollup data costs to - /// account for the empty signature. - pub fn data_gas(&self, input: &Bytes) -> U256 { - let mut rollup_data_gas_cost = U256::from(input.iter().fold(0, |acc, byte| { - acc + if *byte == 0x00 { - ZERO_BYTE_COST - } else { - NON_ZERO_BYTE_COST - } - })); - - // Prior to regolith, an extra 68 non zero bytes were included in the rollup data costs. - if !SPEC::enabled(SpecId::REGOLITH) { - rollup_data_gas_cost += U256::from(NON_ZERO_BYTE_COST).mul(U256::from(68)); - } - - rollup_data_gas_cost - } - - /// Calculate the gas cost of a transaction based on L1 block data posted on L2 - pub fn calculate_tx_l1_cost(&self, input: &Bytes, is_deposit: bool) -> U256 { - let rollup_data_gas_cost = self.data_gas::(input); - - if is_deposit || rollup_data_gas_cost == U256::ZERO { - return U256::ZERO; - } - - rollup_data_gas_cost - .saturating_add(self.l1_fee_overhead) - .saturating_mul(self.l1_base_fee) - .saturating_mul(self.l1_fee_scalar) - .checked_div(U256::from(1_000_000)) - .unwrap_or_default() + /// Fetches the L1 block info from the `L1Block` contract in the database. + pub fn try_fetch(db: &mut DB) -> Result { + let l1_base_fee = db.storage(*L1_BLOCK_CONTRACT, *L1_BASE_FEE_SLOT)?; + let l1_fee_overhead = db.storage(*L1_BLOCK_CONTRACT, *L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(*L1_BLOCK_CONTRACT, *L1_SCALAR_SLOT)?; + + Ok(L1BlockInfo { + l1_base_fee, + l1_fee_overhead, + l1_fee_scalar, + }) } } - -/// Fetches the L1 block info from the `L1Block` contract in the database. -pub fn fetch_l1_block_info(db: &mut DB) -> Result { - let l1_base_fee = db.storage(*L1_BLOCK_CONTRACT, *L1_BASE_FEE_SLOT)?; - let l1_fee_overhead = db.storage(*L1_BLOCK_CONTRACT, *L1_OVERHEAD_SLOT)?; - let l1_fee_scalar = db.storage(*L1_BLOCK_CONTRACT, *L1_SCALAR_SLOT)?; - - Ok(L1BlockInfo { - l1_base_fee, - l1_fee_overhead, - l1_fee_scalar, - }) -} From 2cc96dad53237c55c292d2819706ec5a4e37482d Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 20:24:25 -0400 Subject: [PATCH 06/55] Add helpers for computing the L1 cost of a transaction back --- crates/revm/src/optimism.rs | 45 ++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 5e0a830b13..d60da6553d 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -1,7 +1,12 @@ //! Optimism-specific constants, types, and helpers. +use bytes::Bytes; +use core::ops::Mul; use once_cell::sync::Lazy; -use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, U256}; +use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, Spec, SpecId, U256}; + +const ZERO_BYTE_COST: u64 = 4; +const NON_ZERO_BYTE_COST: u64 = 16; static L1_BASE_FEE_SLOT: Lazy = Lazy::new(|| U256::from(1)); static L1_OVERHEAD_SLOT: Lazy = Lazy::new(|| U256::from(5)); @@ -53,4 +58,42 @@ impl L1BlockInfo { l1_fee_scalar, }) } + + /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero + /// byte and 4 gas per zero byte. + /// + /// Prior to regolith, an extra 68 non-zero bytes were included in the rollup data costs to + /// account for the empty signature. + pub fn data_gas(&self, input: &Bytes) -> U256 { + let mut rollup_data_gas_cost = U256::from(input.iter().fold(0, |acc, byte| { + acc + if *byte == 0x00 { + ZERO_BYTE_COST + } else { + NON_ZERO_BYTE_COST + } + })); + + // Prior to regolith, an extra 68 non zero bytes were included in the rollup data costs. + if !SPEC::enabled(SpecId::REGOLITH) { + rollup_data_gas_cost += U256::from(NON_ZERO_BYTE_COST).mul(U256::from(68)); + } + + rollup_data_gas_cost + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2 + pub fn calculate_tx_l1_cost(&self, input: &Bytes, is_deposit: bool) -> U256 { + let rollup_data_gas_cost = self.data_gas::(input); + + if is_deposit || rollup_data_gas_cost == U256::ZERO { + return U256::ZERO; + } + + rollup_data_gas_cost + .saturating_add(self.l1_fee_overhead) + .saturating_mul(self.l1_base_fee) + .saturating_mul(self.l1_fee_scalar) + .checked_div(U256::from(1_000_000)) + .unwrap_or_default() + } } From 75f8287818ca11df4e7d5eb172f7b6cc39115746 Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 21:40:28 -0400 Subject: [PATCH 07/55] :broom: --- crates/revm/src/evm_impl.rs | 13 ++++++------- crates/revm/src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 975815507a..ddb9dedcfd 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -160,13 +160,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let tx_is_create = env.tx.transact_to.is_create(); let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] - let tx_mint = env.tx.mint; - #[cfg(feature = "optimism")] - let tx_system = env.tx.is_system_transaction; - #[cfg(feature = "optimism")] - let tx_l1_cost = env.tx.l1_cost; - #[cfg(feature = "optimism")] - let is_deposit = env.tx.source_hash.is_some(); + let (tx_mint, tx_system, tx_l1_cost, is_deposit) = ( + env.tx.mint, + env.tx.is_system_transaction, + env.tx.l1_cost, + env.tx.source_hash.is_some(), + ); let initial_gas_spend = initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 8862ea993a..958096ff90 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -45,4 +45,4 @@ pub use inspector::Inspector; // export Optimism types, helpers, and constants #[cfg(feature = "optimism")] -pub use optimism::*; +pub use optimism::{L1BlockInfo, BASE_FEE_RECIPIENT, L1_BLOCK_CONTRACT, L1_FEE_RECIPIENT}; From 4154183a4000d9204a62d7f00628157fadc8101d Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 1 Sep 2023 21:49:02 -0400 Subject: [PATCH 08/55] Enforce runtime config flag for cross-compatibility --- crates/primitives/src/env.rs | 2 +- crates/revm/src/evm_impl.rs | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 9f21cd6498..13cb040888 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -370,7 +370,7 @@ impl Env { // On Optimism, deposit transactions do not have verification on the nonce // nor the balance of the account. #[cfg(feature = "optimism")] - if is_deposit { + if self.cfg.optimism && is_deposit { return Ok(()); } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index ddb9dedcfd..cc03329ce5 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -100,7 +100,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let env = self.env(); #[cfg(feature = "optimism")] - let is_deposit = env.tx.source_hash.is_some(); + let is_deposit = env.cfg.optimism && env.tx.source_hash.is_some(); env.validate_block_env::()?; @@ -108,7 +108,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // no nonce to check, and no need to check if EOA (L1 already verified it for us) // Gas is free, but no refunds! #[cfg(feature = "optimism")] - { + if env.cfg.optimism { if !is_deposit { env.validate_tx::()?; } @@ -200,7 +200,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // If the transaction is not a deposit transaction, subtract the L1 data fee from the // caller's balance directly after minting the requested amount of ETH. - #[cfg(feature = "optimism")] if !is_deposit { if let Some(l1_cost) = tx_l1_cost { journal @@ -297,7 +296,9 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // enabled. // - Regular transactions report their gas used as normal. #[cfg(feature = "optimism")] - if !is_deposit || GSPEC::enabled(SpecId::REGOLITH) { + if self.data.env.cfg.optimism + && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) + { // For regular transactions prior to Regolith and all transactions after // Regolith, gas is reported as normal. gas.erase_cost(ret_gas.remaining()); @@ -325,7 +326,9 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // gas used on failure. Refunds on remaining gas enabled. // - Regular transactions receive a refund on remaining gas as normal. #[cfg(feature = "optimism")] - if !is_deposit || GSPEC::enabled(SpecId::REGOLITH) { + if self.data.env.cfg.optimism + && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) + { gas.erase_cost(ret_gas.remaining()); } } @@ -403,12 +406,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let is_gas_refund_disabled = self.data.env.cfg.is_gas_refund_disabled(); #[cfg(feature = "optimism")] - let is_deposit = self.data.env.tx.source_hash.is_some(); + let is_deposit = self.data.env.cfg.optimism && self.data.env.tx.source_hash.is_some(); // Prior to Regolith, deposit transactions did not receive gas refunds. #[cfg(feature = "optimism")] - let is_gas_refund_disabled = - is_gas_refund_disabled && is_deposit && !SPEC::enabled(SpecId::REGOLITH); + let is_gas_refund_disabled = is_gas_refund_disabled + || (self.data.env.cfg.optimism && is_deposit && !SPEC::enabled(SpecId::REGOLITH)); let gas_refunded = if is_gas_refund_disabled { 0 @@ -435,7 +438,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, // All deposit transactions skip the coinbase tip in favor of paying the // various fee vaults. #[cfg(feature = "optimism")] - let disable_coinbase_tip = disable_coinbase_tip || is_deposit; + let disable_coinbase_tip = + disable_coinbase_tip || (self.data.env.cfg.optimism && is_deposit); // transfer fee to coinbase/beneficiary. if !disable_coinbase_tip { From 9bb0c49ead6bc219ae667141d057a818208d9078 Mon Sep 17 00:00:00 2001 From: clabby Date: Sat, 2 Sep 2023 16:21:26 -0400 Subject: [PATCH 09/55] style: Use env rather than passing a flag --- crates/primitives/src/env.rs | 8 ++------ crates/revm/src/evm_impl.rs | 6 +----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 13cb040888..37f12fbab4 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -355,11 +355,7 @@ impl Env { /// Validate transaction against state. #[inline] - pub fn validate_tx_against_state( - &self, - account: &Account, - #[cfg(feature = "optimism")] is_deposit: bool, - ) -> Result<(), InvalidTransaction> { + pub fn validate_tx_against_state(&self, account: &Account) -> Result<(), InvalidTransaction> { // EIP-3607: Reject transactions from senders with deployed code // This EIP is introduced after london but there was no collision in past // so we can leave it enabled always @@ -370,7 +366,7 @@ impl Env { // On Optimism, deposit transactions do not have verification on the nonce // nor the balance of the account. #[cfg(feature = "optimism")] - if self.cfg.optimism && is_deposit { + if self.cfg.optimism && self.tx.source_hash.is_some() { return Ok(()); } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index cc03329ce5..45c1b05556 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -142,11 +142,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact .load_account(tx_caller, self.data.db) .map_err(EVMError::Database)?; - self.data.env.validate_tx_against_state( - caller_account, - #[cfg(feature = "optimism")] - is_deposit, - )?; + self.data.env.validate_tx_against_state(caller_account)?; Ok(()) } From a31c31c968fc5b0b3aa4e7db6e9f7b3a4c22f361 Mon Sep 17 00:00:00 2001 From: clabby Date: Tue, 5 Sep 2023 11:57:57 -0400 Subject: [PATCH 10/55] review: Address first few comments --- Cargo.lock | 1 - crates/primitives/src/env.rs | 13 +++++++++++++ crates/revm/Cargo.toml | 2 -- crates/revm/src/evm_impl.rs | 27 ++------------------------- crates/revm/src/optimism.rs | 27 ++++++++++++--------------- 5 files changed, 27 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bdcb2f8a4..ae802d0394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2215,7 +2215,6 @@ dependencies = [ "futures", "hex", "hex-literal", - "once_cell", "rayon", "revm-interpreter", "revm-precompile", diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 37f12fbab4..e22e15549d 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -301,6 +301,19 @@ impl Env { /// Return initial spend gas (Gas needed to execute transaction). #[inline] pub fn validate_tx(&self) -> Result<(), InvalidTransaction> { + #[cfg(feature = "optimism")] + if self.cfg.optimism { + // Do not allow for a system transaction to be processed if Regolith is enabled. + if self.tx.is_system_transaction.unwrap_or(false) && SPEC::enabled(SpecId::REGOLITH) { + return Err(InvalidTransaction::DepositSystemTxPostRegolith); + } + + // Do not perform any extra validation for deposit transactions, they are pre-verified on L1. + if self.tx.source_hash.is_some() { + return Ok(()); + } + } + let gas_limit = self.tx.gas_limit; let effective_gas_price = self.effective_gas_price(); let is_create = self.tx.transact_to.is_create(); diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index b54598dd60..deb223ae3e 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -15,8 +15,6 @@ revm-interpreter = { path = "../interpreter", version = "1.1.2", default-feature #misc auto_impl = { version = "1.1", default-features = false } -once_cell = "1.18.0" -bytes = "1.4.0" # Optional serde = { version = "1.0", features = ["derive", "rc"], optional = true } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 45c1b05556..fba4a15b24 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -99,30 +99,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact fn preverify_transaction(&mut self) -> Result<(), EVMError> { let env = self.env(); - #[cfg(feature = "optimism")] - let is_deposit = env.cfg.optimism && env.tx.source_hash.is_some(); - env.validate_block_env::()?; - - // If the transaction is a deposit transaction on Optimism, there are no fee fields to check, - // no nonce to check, and no need to check if EOA (L1 already verified it for us) - // Gas is free, but no refunds! - #[cfg(feature = "optimism")] - if env.cfg.optimism { - if !is_deposit { - env.validate_tx::()?; - } - - // Do not allow for a system transaction to be processed if Regolith is enabled. - if is_deposit - && env.tx.is_system_transaction.unwrap_or(false) - && GSPEC::enabled(SpecId::REGOLITH) - { - return Err(InvalidTransaction::DepositSystemTxPostRegolith.into()); - } - } - - #[cfg(not(feature = "optimism"))] env.validate_tx::()?; let tx_caller = env.tx.caller; @@ -474,7 +451,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let Ok((l1_fee_vault_account, _)) = self .data .journaled_state - .load_account(*optimism::L1_FEE_RECIPIENT, self.data.db) + .load_account(optimism::L1_FEE_RECIPIENT.into(), self.data.db) else { panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); }; @@ -486,7 +463,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let Ok((base_fee_vault_account, _)) = self .data .journaled_state - .load_account(*optimism::BASE_FEE_RECIPIENT, self.data.db) + .load_account(optimism::BASE_FEE_RECIPIENT.into(), self.data.db) else { panic!("[OPTIMISM] Failed to load Base Fee Vault account"); }; diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index d60da6553d..df3348a432 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -1,28 +1,25 @@ //! Optimism-specific constants, types, and helpers. -use bytes::Bytes; use core::ops::Mul; -use once_cell::sync::Lazy; -use revm_interpreter::primitives::{db::Database, hex_literal::hex, Address, Spec, SpecId, U256}; +use revm_interpreter::primitives::{ + db::Database, hex_literal::hex, Bytes, Spec, SpecId, B160, U256, +}; const ZERO_BYTE_COST: u64 = 4; const NON_ZERO_BYTE_COST: u64 = 16; -static L1_BASE_FEE_SLOT: Lazy = Lazy::new(|| U256::from(1)); -static L1_OVERHEAD_SLOT: Lazy = Lazy::new(|| U256::from(5)); -static L1_SCALAR_SLOT: Lazy = Lazy::new(|| U256::from(6)); +const L1_BASE_FEE_SLOT: U256 = U256::from_limbs([1u64, 0, 0, 0]); +const L1_OVERHEAD_SLOT: U256 = U256::from_limbs([5u64, 0, 0, 0]); +const L1_SCALAR_SLOT: U256 = U256::from_limbs([6u64, 0, 0, 0]); /// The address of L1 fee recipient. -pub static L1_FEE_RECIPIENT: Lazy
= - Lazy::new(|| Address::from_slice(&hex!("420000000000000000000000000000000000001A"))); +pub const L1_FEE_RECIPIENT: B160 = B160(hex!("420000000000000000000000000000000000001A")); /// The address of the base fee recipient. -pub static BASE_FEE_RECIPIENT: Lazy
= - Lazy::new(|| Address::from_slice(&hex!("4200000000000000000000000000000000000019"))); +pub const BASE_FEE_RECIPIENT: B160 = B160(hex!("4200000000000000000000000000000000000019")); /// The address of the L1Block contract. -pub static L1_BLOCK_CONTRACT: Lazy
= - Lazy::new(|| Address::from_slice(&hex!("4200000000000000000000000000000000000015"))); +pub const L1_BLOCK_CONTRACT: B160 = B160(hex!("4200000000000000000000000000000000000015")); /// L1 block info /// @@ -48,9 +45,9 @@ pub struct L1BlockInfo { impl L1BlockInfo { /// Fetches the L1 block info from the `L1Block` contract in the database. pub fn try_fetch(db: &mut DB) -> Result { - let l1_base_fee = db.storage(*L1_BLOCK_CONTRACT, *L1_BASE_FEE_SLOT)?; - let l1_fee_overhead = db.storage(*L1_BLOCK_CONTRACT, *L1_OVERHEAD_SLOT)?; - let l1_fee_scalar = db.storage(*L1_BLOCK_CONTRACT, *L1_SCALAR_SLOT)?; + let l1_base_fee = db.storage(L1_BLOCK_CONTRACT.into(), L1_BASE_FEE_SLOT)?; + let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT.into(), L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT.into(), L1_SCALAR_SLOT)?; Ok(L1BlockInfo { l1_base_fee, From 9490270cc55e0fe9148ab22b42fb291a59a93a91 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 15:54:17 -0400 Subject: [PATCH 11/55] Flatten optimism hoisted tx fields --- crates/primitives/src/env.rs | 35 ++++++++++++++++++----------------- crates/revm/src/evm_impl.rs | 17 +++++++++-------- crates/revm/src/optimism.rs | 6 +++--- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index e22e15549d..cad3a4329d 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -30,6 +30,16 @@ pub struct BlockEnv { pub gas_limit: U256, } +#[derive(Clone, Debug, Default)] +#[cfg(feature = "optimism")] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct OptimismFields { + pub source_hash: Option, + pub mint: Option, + pub is_system_transaction: Option, + pub l1_cost: Option, +} + #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TxEnv { @@ -45,14 +55,9 @@ pub struct TxEnv { pub chain_id: Option, pub nonce: Option, pub access_list: Vec<(B160, Vec)>, + #[cfg_attr(feature = "serde", serde(flatten))] #[cfg(feature = "optimism")] - pub source_hash: Option, - #[cfg(feature = "optimism")] - pub mint: Option, - #[cfg(feature = "optimism")] - pub is_system_transaction: Option, - #[cfg(feature = "optimism")] - pub l1_cost: Option, + pub optimism: OptimismFields, } #[derive(Clone, Debug)] @@ -261,13 +266,7 @@ impl Default for TxEnv { nonce: None, access_list: Vec::new(), #[cfg(feature = "optimism")] - source_hash: None, - #[cfg(feature = "optimism")] - mint: None, - #[cfg(feature = "optimism")] - is_system_transaction: None, - #[cfg(feature = "optimism")] - l1_cost: None, + optimism: OptimismFields::default(), } } } @@ -304,12 +303,14 @@ impl Env { #[cfg(feature = "optimism")] if self.cfg.optimism { // Do not allow for a system transaction to be processed if Regolith is enabled. - if self.tx.is_system_transaction.unwrap_or(false) && SPEC::enabled(SpecId::REGOLITH) { + if self.tx.optimism.is_system_transaction.unwrap_or(false) + && SPEC::enabled(SpecId::REGOLITH) + { return Err(InvalidTransaction::DepositSystemTxPostRegolith); } // Do not perform any extra validation for deposit transactions, they are pre-verified on L1. - if self.tx.source_hash.is_some() { + if self.tx.optimism.source_hash.is_some() { return Ok(()); } } @@ -379,7 +380,7 @@ impl Env { // On Optimism, deposit transactions do not have verification on the nonce // nor the balance of the account. #[cfg(feature = "optimism")] - if self.cfg.optimism && self.tx.source_hash.is_some() { + if self.cfg.optimism && self.tx.optimism.source_hash.is_some() { return Ok(()); } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index fba4a15b24..f04028f64a 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -134,10 +134,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] let (tx_mint, tx_system, tx_l1_cost, is_deposit) = ( - env.tx.mint, - env.tx.is_system_transaction, - env.tx.l1_cost, - env.tx.source_hash.is_some(), + env.tx.optimism.mint, + env.tx.optimism.is_system_transaction, + env.tx.optimism.l1_cost, + env.tx.optimism.source_hash.is_some(), ); let initial_gas_spend = @@ -379,7 +379,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let is_gas_refund_disabled = self.data.env.cfg.is_gas_refund_disabled(); #[cfg(feature = "optimism")] - let is_deposit = self.data.env.cfg.optimism && self.data.env.tx.source_hash.is_some(); + let is_deposit = + self.data.env.cfg.optimism && self.data.env.tx.optimism.source_hash.is_some(); // Prior to Regolith, deposit transactions did not receive gas refunds. #[cfg(feature = "optimism")] @@ -447,11 +448,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, }; // Send the L1 cost of the transaction to the L1 Fee Vault. - if let Some(l1_cost) = self.data.env.tx.l1_cost { + if let Some(l1_cost) = self.data.env.tx.optimism.l1_cost { let Ok((l1_fee_vault_account, _)) = self .data .journaled_state - .load_account(optimism::L1_FEE_RECIPIENT.into(), self.data.db) + .load_account(optimism::L1_FEE_RECIPIENT, self.data.db) else { panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); }; @@ -463,7 +464,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, let Ok((base_fee_vault_account, _)) = self .data .journaled_state - .load_account(optimism::BASE_FEE_RECIPIENT.into(), self.data.db) + .load_account(optimism::BASE_FEE_RECIPIENT, self.data.db) else { panic!("[OPTIMISM] Failed to load Base Fee Vault account"); }; diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index df3348a432..42ba9f06c5 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -45,9 +45,9 @@ pub struct L1BlockInfo { impl L1BlockInfo { /// Fetches the L1 block info from the `L1Block` contract in the database. pub fn try_fetch(db: &mut DB) -> Result { - let l1_base_fee = db.storage(L1_BLOCK_CONTRACT.into(), L1_BASE_FEE_SLOT)?; - let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT.into(), L1_OVERHEAD_SLOT)?; - let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT.into(), L1_SCALAR_SLOT)?; + let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; + let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; Ok(L1BlockInfo { l1_base_fee, From 8f0caa1b792ee6368efc79d448d711ee8e093469 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 18:19:13 -0400 Subject: [PATCH 12/55] feat flag ontop --- crates/primitives/src/env.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index cad3a4329d..73c320e654 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -29,9 +29,8 @@ pub struct BlockEnv { pub basefee: U256, pub gas_limit: U256, } - -#[derive(Clone, Debug, Default)] #[cfg(feature = "optimism")] +#[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct OptimismFields { pub source_hash: Option, From 128e440c5edef97cfbbcb59be3f4ca6c14e6231e Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 16:34:50 -0400 Subject: [PATCH 13/55] Refactor l1 cost and mint computations --- crates/revm/src/evm_impl.rs | 85 ++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index f04028f64a..b1c1e652dc 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -91,6 +91,52 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } Ok(()) } + + /// If the transaction is not a deposit transaction, subtract the L1 data fee from the + /// caller's balance directly after minting the requested amount of ETH. + #[cfg(feature = "optimism")] + fn remove_l1_cost( + is_deposit: bool, + tx_caller: B160, + tx_l1_cost: Option, + db: &mut DB, + journal: &mut JournaledState, + ) -> Result<(), EVMError> { + if is_deposit { + return Ok(()); + } + if let Some(l1_cost) = tx_l1_cost { + let acc = journal + .load_account(tx_caller, db) + .map_err(EVMError::Database)? + .0; + let res = acc.info.balance.saturating_sub(l1_cost); + acc.info.balance = res; + } + Ok(()) + } + + /// If the transaction is a deposit with a `mint` value, add the mint value + /// in wei to the caller's balance. This should be persisted to the database + /// prior to the rest of execution. + #[cfg(feature = "optimism")] + fn commit_mint_value( + tx_caller: B160, + tx_mint: Option, + db: &mut DB, + journal: &mut JournaledState, + ) -> Result<(), EVMError> { + if let Some(mint) = tx_mint { + journal + .load_account(tx_caller, db) + .map_err(EVMError::Database)? + .0 + .info + .balance += U256::from(mint); + journal.checkpoint(); + } + Ok(()) + } } impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact @@ -158,31 +204,20 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact #[cfg(feature = "optimism")] if self.data.env.cfg.optimism { - // If the transaction is a deposit with a `Some` `mint` value, add the minted value - // in wei to the caller's balance. This should be persisted to the database prior - // to the rest of execution below. - if let Some(mint) = tx_mint { - journal - .load_account(tx_caller, self.data.db) - .map_err(EVMError::Database)? - .0 - .info - .balance += U256::from(mint); - journal.checkpoint(); - } - - // If the transaction is not a deposit transaction, subtract the L1 data fee from the - // caller's balance directly after minting the requested amount of ETH. - if !is_deposit { - if let Some(l1_cost) = tx_l1_cost { - journal - .load_account(tx_caller, self.data.db) - .map_err(EVMError::Database)? - .0 - .info - .balance -= l1_cost; - } - } + EVMImpl::::commit_mint_value( + tx_caller, + tx_mint, + self.data.db, + journal, + )?; + + EVMImpl::::remove_l1_cost( + is_deposit, + tx_caller, + tx_l1_cost, + self.data.db, + journal, + )?; } let (caller_account, _) = journal From 6b868b3828332b625ffbc6f71aded6b00a25a5b4 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 18:43:29 -0400 Subject: [PATCH 14/55] l1 cost erroring --- crates/revm/src/evm_impl.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index b1c1e652dc..6468842546 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -110,8 +110,21 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, .load_account(tx_caller, db) .map_err(EVMError::Database)? .0; - let res = acc.info.balance.saturating_sub(l1_cost); - acc.info.balance = res; + if l1_cost.gt(&acc.info.balance) { + let x = l1_cost.as_limbs(); + let u64_cost = if x[1] == 0 && x[2] == 0 && x[3] == 0 { + x[0] + } else { + u64::MAX + }; + return Err(EVMError::Transaction( + InvalidTransaction::LackOfFundForMaxFee { + fee: u64_cost, + balance: acc.info.balance, + }, + )); + } + acc.info.balance = acc.info.balance.saturating_sub(l1_cost); } Ok(()) } From d64258225c499e49436d177f0cdacf29424d67ac Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 17:28:00 -0400 Subject: [PATCH 15/55] Refactor gas usage functions --- crates/revm/src/evm_impl.rs | 179 +++++++++++++++++++++--------------- 1 file changed, 106 insertions(+), 73 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 6468842546..3fd56f0d3e 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -150,6 +150,99 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } Ok(()) } + + /// Set gas to the gas limit and spend it all. + #[cfg(not(feature = "optimism"))] + #[inline] + fn use_gas( + &mut self, + gas_limit: u64, + ret_gas: Gas, + exit_reason: InstructionResult, + ) -> Result> { + let mut gas = Gas::new(gas_limit); + gas.record_cost(gas_limit); + if crate::USE_GAS { + match exit_reason { + return_ok!() => { + gas.erase_cost(ret_gas.remaining()); + gas.record_refund(ret_gas.refunded()); + } + return_revert!() => { + gas.erase_cost(ret_gas.remaining()); + } + _ => {} + } + } + Ok(gas) + } + + /// Set gas to the gas limit and spend it all. + #[cfg(feature = "optimism")] + #[inline] + fn use_gas( + &mut self, + is_deposit: bool, + tx_system: Option, + gas_limit: u64, + ret_gas: Gas, + exit_reason: InstructionResult, + ) -> Result> { + let mut gas = Gas::new(gas_limit); + gas.record_cost(gas_limit); + if crate::USE_GAS { + match exit_reason { + return_ok!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + if self.data.env.cfg.optimism + && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) + { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(ret_gas.remaining()); + gas.record_refund(ret_gas.refunded()); + } else if is_deposit && tx_system.unwrap_or(false) { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(gas_limit); + } + } + return_revert!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if self.data.env.cfg.optimism + && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) + { + gas.erase_cost(ret_gas.remaining()); + } + } + _ => {} + } + } + Ok(gas) + } } impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact @@ -191,13 +284,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let tx_gas_limit = env.tx.gas_limit; let tx_is_create = env.tx.transact_to.is_create(); let effective_gas_price = env.effective_gas_price(); + + #[cfg(feature = "optimism")] + let tx_mint = env.tx.optimism.mint; + #[cfg(feature = "optimism")] + let tx_system = env.tx.optimism.is_system_transaction; + #[cfg(feature = "optimism")] + let tx_l1_cost = env.tx.optimism.l1_cost; #[cfg(feature = "optimism")] - let (tx_mint, tx_system, tx_l1_cost, is_deposit) = ( - env.tx.optimism.mint, - env.tx.optimism.is_system_transaction, - env.tx.optimism.l1_cost, - env.tx.optimism.source_hash.is_some(), - ); + let is_deposit = env.tx.optimism.source_hash.is_some(); let initial_gas_spend = initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); @@ -289,73 +384,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact } }; - // set gas with gas limit and spend it all. Gas is going to be reimbursed when - // transaction is returned successfully. - let mut gas = Gas::new(tx_gas_limit); - gas.record_cost(tx_gas_limit); - - if crate::USE_GAS { - match exit_reason { - return_ok!() => { - #[cfg(not(feature = "optimism"))] - { - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); - } - - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (success path): - // - Deposit transactions (non-system) report their gas limit as the usage. - // No refunds. - // - Deposit transactions (system) report 0 gas used. No refunds. - // - Regular transactions report gas usage as normal. - // - Regolith (success path): - // - Deposit transactions (all) report their gas used as normal. Refunds - // enabled. - // - Regular transactions report their gas used as normal. - #[cfg(feature = "optimism")] - if self.data.env.cfg.optimism - && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) - { - // For regular transactions prior to Regolith and all transactions after - // Regolith, gas is reported as normal. - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); - } else if is_deposit && tx_system.unwrap_or(false) { - // System transactions were a special type of deposit transaction in - // the Bedrock hardfork that did not incur any gas costs. - gas.erase_cost(tx_gas_limit); - } - } - return_revert!() => { - #[cfg(not(feature = "optimism"))] - gas.erase_cost(ret_gas.remaining()); - - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (revert path): - // - Deposit transactions (all) report the gas limit as the amount of gas - // used on failure. No refunds. - // - Regular transactions receive a refund on remaining gas as normal. - // - Regolith (revert path): - // - Deposit transactions (all) report the actual gas used as the amount of - // gas used on failure. Refunds on remaining gas enabled. - // - Regular transactions receive a refund on remaining gas as normal. - #[cfg(feature = "optimism")] - if self.data.env.cfg.optimism - && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) - { - gas.erase_cost(ret_gas.remaining()); - } - } - _ => {} - } - } + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + #[cfg(not(feature = "optimism"))] + let gas = self.use_gas(tx_gas_limit, ret_gas, exit_reason)?; + #[cfg(feature = "optimism")] + let gas = self.use_gas(is_deposit, tx_system, tx_gas_limit, ret_gas, exit_reason)?; let (state, logs, gas_used, gas_refunded) = self.finalize::(&gas); From 868f593f2e77d4a1f95d8a62ca558ca4b844473d Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 19:06:47 -0400 Subject: [PATCH 16/55] Rip gas construction back to the transact --- crates/revm/src/evm_impl.rs | 42 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 3fd56f0d3e..af9900856f 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -156,12 +156,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, #[inline] fn use_gas( &mut self, + gas: &mut Gas, gas_limit: u64, ret_gas: Gas, exit_reason: InstructionResult, - ) -> Result> { - let mut gas = Gas::new(gas_limit); - gas.record_cost(gas_limit); + ) -> Result<(), EVMError> { if crate::USE_GAS { match exit_reason { return_ok!() => { @@ -174,7 +173,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, _ => {} } } - Ok(gas) + Ok(()) } /// Set gas to the gas limit and spend it all. @@ -182,14 +181,13 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, #[inline] fn use_gas( &mut self, + gas: &mut Gas, is_deposit: bool, tx_system: Option, gas_limit: u64, ret_gas: Gas, exit_reason: InstructionResult, - ) -> Result> { - let mut gas = Gas::new(gas_limit); - gas.record_cost(gas_limit); + ) -> Result<(), EVMError> { if crate::USE_GAS { match exit_reason { return_ok!() => { @@ -241,7 +239,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, _ => {} } } - Ok(gas) + Ok(()) } } @@ -286,13 +284,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] - let tx_mint = env.tx.optimism.mint; - #[cfg(feature = "optimism")] - let tx_system = env.tx.optimism.is_system_transaction; - #[cfg(feature = "optimism")] - let tx_l1_cost = env.tx.optimism.l1_cost; - #[cfg(feature = "optimism")] - let is_deposit = env.tx.optimism.source_hash.is_some(); + let (tx_mint, tx_system, tx_l1_cost, is_deposit) = ( + env.tx.optimism.mint, + env.tx.optimism.is_system_transaction, + env.tx.optimism.l1_cost, + env.tx.optimism.source_hash.is_some(), + ); let initial_gas_spend = initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); @@ -385,10 +382,21 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact }; // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + let mut gas = Gas::new(tx_gas_limit); + gas.record_cost(tx_gas_limit); + #[cfg(not(feature = "optimism"))] - let gas = self.use_gas(tx_gas_limit, ret_gas, exit_reason)?; + self.use_gas(&mut gas, tx_gas_limit, ret_gas, exit_reason)?; + #[cfg(feature = "optimism")] - let gas = self.use_gas(is_deposit, tx_system, tx_gas_limit, ret_gas, exit_reason)?; + self.use_gas( + &mut gas, + is_deposit, + tx_system, + tx_gas_limit, + ret_gas, + exit_reason, + )?; let (state, logs, gas_used, gas_refunded) = self.finalize::(&gas); From 8eab1ad46fb31876a7e76b636d500cd351e5f611 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 19:12:15 -0400 Subject: [PATCH 17/55] Rip out crate use gas --- crates/revm/src/evm_impl.rs | 130 +++++++++++++++++------------------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index af9900856f..43061ce02c 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -161,17 +161,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ret_gas: Gas, exit_reason: InstructionResult, ) -> Result<(), EVMError> { - if crate::USE_GAS { - match exit_reason { - return_ok!() => { - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); - } - return_revert!() => { - gas.erase_cost(ret_gas.remaining()); - } - _ => {} + match exit_reason { + return_ok!() => { + gas.erase_cost(ret_gas.remaining()); + gas.record_refund(ret_gas.refunded()); + } + return_revert!() => { + gas.erase_cost(ret_gas.remaining()); } + _ => {} } Ok(()) } @@ -188,56 +186,50 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, ret_gas: Gas, exit_reason: InstructionResult, ) -> Result<(), EVMError> { - if crate::USE_GAS { - match exit_reason { - return_ok!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (success path): - // - Deposit transactions (non-system) report their gas limit as the usage. - // No refunds. - // - Deposit transactions (system) report 0 gas used. No refunds. - // - Regular transactions report gas usage as normal. - // - Regolith (success path): - // - Deposit transactions (all) report their gas used as normal. Refunds - // enabled. - // - Regular transactions report their gas used as normal. - if self.data.env.cfg.optimism - && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) - { - // For regular transactions prior to Regolith and all transactions after - // Regolith, gas is reported as normal. - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); - } else if is_deposit && tx_system.unwrap_or(false) { - // System transactions were a special type of deposit transaction in - // the Bedrock hardfork that did not incur any gas costs. - gas.erase_cost(gas_limit); - } + match exit_reason { + return_ok!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + if self.data.env.cfg.optimism && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(ret_gas.remaining()); + gas.record_refund(ret_gas.refunded()); + } else if is_deposit && tx_system.unwrap_or(false) { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(gas_limit); } - return_revert!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (revert path): - // - Deposit transactions (all) report the gas limit as the amount of gas - // used on failure. No refunds. - // - Regular transactions receive a refund on remaining gas as normal. - // - Regolith (revert path): - // - Deposit transactions (all) report the actual gas used as the amount of - // gas used on failure. Refunds on remaining gas enabled. - // - Regular transactions receive a refund on remaining gas as normal. - if self.data.env.cfg.optimism - && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) - { - gas.erase_cost(ret_gas.remaining()); - } + } + return_revert!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if self.data.env.cfg.optimism && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) { + gas.erase_cost(ret_gas.remaining()); } - _ => {} } + _ => {} } Ok(()) } @@ -385,18 +377,20 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let mut gas = Gas::new(tx_gas_limit); gas.record_cost(tx_gas_limit); - #[cfg(not(feature = "optimism"))] - self.use_gas(&mut gas, tx_gas_limit, ret_gas, exit_reason)?; + if crate::USE_GAS { + #[cfg(not(feature = "optimism"))] + self.use_gas(&mut gas, tx_gas_limit, ret_gas, exit_reason)?; - #[cfg(feature = "optimism")] - self.use_gas( - &mut gas, - is_deposit, - tx_system, - tx_gas_limit, - ret_gas, - exit_reason, - )?; + #[cfg(feature = "optimism")] + self.use_gas( + &mut gas, + is_deposit, + tx_system, + tx_gas_limit, + ret_gas, + exit_reason, + )?; + } let (state, logs, gas_used, gas_refunded) = self.finalize::(&gas); From 063b4e61796f1eaea7f979c3dde86fb2557f8afe Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Tue, 5 Sep 2023 22:43:03 -0400 Subject: [PATCH 18/55] push gas usage unit logic into the gas impl --- crates/interpreter/src/gas.rs | 79 ++++++++++++++++++++++ crates/revm/src/evm_impl.rs | 122 ++++++++-------------------------- 2 files changed, 106 insertions(+), 95 deletions(-) diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index 0cd45e1171..acc424f900 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -93,6 +93,85 @@ impl Gas { true } + /// Consumes the remaining gas. + #[cfg(not(feature = "optimism"))] + #[inline] + pub fn consume_gas(&mut self, ret_gas: Gas) { + self.erase_cost(ret_gas.remaining()); + self.record_refund(ret_gas.refunded()); + } + + /// Consume the revert gas. + #[cfg(not(feature = "optimism"))] + #[inline] + pub fn consume_revert_gas(&mut self, ret_gas: Gas) { + self.erase_cost(ret_gas.remaining()); + } + + /// Consume revert gas limit. + #[cfg(feature = "optimism")] + #[inline] + pub fn consume_revert_gas( + &mut self, + is_optimism: bool, + is_deposit: bool, + is_regolith: bool, + ret_gas: Gas, + ) { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if is_optimism && (!is_deposit || is_regolith) { + self.erase_cost(ret_gas.remaining()); + } + } + + /// Consume remaining gas. + #[cfg(feature = "optimism")] + #[inline] + pub fn consume_gas( + &mut self, + is_optimism: bool, + is_deposit: bool, + is_regolith: bool, + tx_system: Option, + gas_limit: u64, + ret_gas: Gas, + ) { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + if is_optimism && (!is_deposit || is_regolith) { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + self.erase_cost(ret_gas.remaining()); + self.record_refund(ret_gas.refunded()); + } else if is_deposit && tx_system.unwrap_or(false) { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + self.erase_cost(gas_limit); + } + } + /// used in memory_resize! macro to record gas used for memory expansion. #[inline] pub fn record_memory(&mut self, gas_memory: u64) -> bool { diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 43061ce02c..420e8405e9 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -150,89 +150,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } Ok(()) } - - /// Set gas to the gas limit and spend it all. - #[cfg(not(feature = "optimism"))] - #[inline] - fn use_gas( - &mut self, - gas: &mut Gas, - gas_limit: u64, - ret_gas: Gas, - exit_reason: InstructionResult, - ) -> Result<(), EVMError> { - match exit_reason { - return_ok!() => { - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); - } - return_revert!() => { - gas.erase_cost(ret_gas.remaining()); - } - _ => {} - } - Ok(()) - } - - /// Set gas to the gas limit and spend it all. - #[cfg(feature = "optimism")] - #[inline] - fn use_gas( - &mut self, - gas: &mut Gas, - is_deposit: bool, - tx_system: Option, - gas_limit: u64, - ret_gas: Gas, - exit_reason: InstructionResult, - ) -> Result<(), EVMError> { - match exit_reason { - return_ok!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (success path): - // - Deposit transactions (non-system) report their gas limit as the usage. - // No refunds. - // - Deposit transactions (system) report 0 gas used. No refunds. - // - Regular transactions report gas usage as normal. - // - Regolith (success path): - // - Deposit transactions (all) report their gas used as normal. Refunds - // enabled. - // - Regular transactions report their gas used as normal. - if self.data.env.cfg.optimism && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) { - // For regular transactions prior to Regolith and all transactions after - // Regolith, gas is reported as normal. - gas.erase_cost(ret_gas.remaining()); - gas.record_refund(ret_gas.refunded()); - } else if is_deposit && tx_system.unwrap_or(false) { - // System transactions were a special type of deposit transaction in - // the Bedrock hardfork that did not incur any gas costs. - gas.erase_cost(gas_limit); - } - } - return_revert!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (revert path): - // - Deposit transactions (all) report the gas limit as the amount of gas - // used on failure. No refunds. - // - Regular transactions receive a refund on remaining gas as normal. - // - Regolith (revert path): - // - Deposit transactions (all) report the actual gas used as the amount of - // gas used on failure. Refunds on remaining gas enabled. - // - Regular transactions receive a refund on remaining gas as normal. - if self.data.env.cfg.optimism && (!is_deposit || GSPEC::enabled(SpecId::REGOLITH)) { - gas.erase_cost(ret_gas.remaining()); - } - } - _ => {} - } - Ok(()) - } } impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact @@ -378,18 +295,33 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact gas.record_cost(tx_gas_limit); if crate::USE_GAS { - #[cfg(not(feature = "optimism"))] - self.use_gas(&mut gas, tx_gas_limit, ret_gas, exit_reason)?; - - #[cfg(feature = "optimism")] - self.use_gas( - &mut gas, - is_deposit, - tx_system, - tx_gas_limit, - ret_gas, - exit_reason, - )?; + match exit_reason { + return_ok!() => { + #[cfg(not(feature = "optimism"))] + gas.consume_gas(ret_gas); + #[cfg(feature = "optimism")] + gas.consume_gas( + self.data.env.cfg.optimism, + is_deposit, + GSPEC::enabled(SpecId::REGOLITH), + tx_system, + tx_gas_limit, + ret_gas, + ); + } + return_revert!() => { + #[cfg(not(feature = "optimism"))] + gas.consume_revert_gas(ret_gas); + #[cfg(feature = "optimism")] + gas.consume_revert_gas( + self.data.env.cfg.optimism, + is_deposit, + GSPEC::enabled(SpecId::REGOLITH), + ret_gas, + ); + } + _ => {} + } } let (state, logs, gas_used, gas_refunded) = self.finalize::(&gas); From b0d703ca83006772dff77c4e72efe4e7b4e72950 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 14:34:33 -0400 Subject: [PATCH 19/55] Further document the cfg env optimism bool field. --- crates/primitives/src/env.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index e348427f04..6201fa9941 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -135,7 +135,11 @@ pub struct CfgEnv { #[cfg(feature = "optional_no_base_fee")] pub disable_base_fee: bool, /// Enables Optimism's execution changes for deposit transactions and fee - /// collection. + /// collection. Hot toggling the optimism field at runtime gives + /// applications built ontop of revm the ability to switch optimism + /// execution on and off. This allows for features like multichain + /// fork testing. Setting this to false will disable all optimism + /// execution changes regardless of the optimism feature flag. #[cfg(feature = "optimism")] pub optimism: bool, } From 04043856bcdd42828eb4970728d26c447d8d6d27 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 14:39:27 -0400 Subject: [PATCH 20/55] Reword --- crates/primitives/src/env.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 6201fa9941..6001e8162c 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -135,11 +135,11 @@ pub struct CfgEnv { #[cfg(feature = "optional_no_base_fee")] pub disable_base_fee: bool, /// Enables Optimism's execution changes for deposit transactions and fee - /// collection. Hot toggling the optimism field at runtime gives - /// applications built ontop of revm the ability to switch optimism - /// execution on and off. This allows for features like multichain - /// fork testing. Setting this to false will disable all optimism - /// execution changes regardless of the optimism feature flag. + /// collection. Hot toggling the optimism field gives applications built + /// on revm the ability to switch optimism execution on and off at runtime, + /// allowing for features like multichain fork testing. Setting this field + /// to false will disable all optimism execution changes regardless of + /// compilation with the optimism feature flag. #[cfg(feature = "optimism")] pub optimism: bool, } From d9cd733d0aa7e031a8f1859090e7f3a2036d47af Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 15:03:51 -0400 Subject: [PATCH 21/55] Add deposit sys tx docs --- crates/primitives/src/result.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs index 4549b09560..e20d876698 100644 --- a/crates/primitives/src/result.rs +++ b/crates/primitives/src/result.rs @@ -183,6 +183,8 @@ pub enum InvalidTransaction { /// Access list is not supported is not supported /// for blocks before Berlin hardfork. AccessListNotSupported, + /// System transactions are not supported + /// post-regolith hardfork. #[cfg(feature = "optimism")] DepositSystemTxPostRegolith, } From cee3daebabddfe375b713924ccf5cca4d51fd590 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 18:04:00 -0400 Subject: [PATCH 22/55] Fix the spec enabled function and add unit tests. --- crates/primitives/src/specification.rs | 38 ++++++++++++++++++++++++-- crates/revm/src/optimism.rs | 29 ++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/crates/primitives/src/specification.rs b/crates/primitives/src/specification.rs index 6f04c2b1dd..f5858ca617 100644 --- a/crates/primitives/src/specification.rs +++ b/crates/primitives/src/specification.rs @@ -77,14 +77,19 @@ pub trait Spec: Sized { #[inline(always)] fn enabled(spec_id: SpecId) -> bool { + // If the Spec is Bedrock or Regolith, and the input is not Bedrock or Regolith, + // then no hardforks should be enabled after the merge. + let is_self_optimism = + Self::SPEC_ID == SpecId::BEDROCK || Self::SPEC_ID == SpecId::REGOLITH; + let input_not_optimism = spec_id != SpecId::BEDROCK && spec_id != SpecId::REGOLITH; + let after_merge = spec_id > SpecId::MERGE; + // Optimism's Bedrock and Regolith hardforks implement changes on top of the Merge // hardfork. This function is modified to preserve the original behavior of the // spec IDs without having to put hardforks past Merge under // `#[cfg(not(feature = "optimism"))]`. #[cfg(feature = "optimism")] - if (Self::SPEC_ID == SpecId::BEDROCK || Self::SPEC_ID == SpecId::REGOLITH) - && spec_id > SpecId::MERGE - { + if is_self_optimism && input_not_optimism && after_merge { return false; } @@ -128,3 +133,30 @@ spec!(LATEST, LatestSpec); spec!(BEDROCK, BedrockSpec); #[cfg(feature = "optimism")] spec!(REGOLITH, RegolithSpec); + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "optimism")] + #[test] + fn test_bedrock_post_merge_hardforks() { + assert!(BedrockSpec::enabled(SpecId::MERGE)); + assert!(!BedrockSpec::enabled(SpecId::SHANGHAI)); + assert!(!BedrockSpec::enabled(SpecId::CANCUN)); + assert!(!BedrockSpec::enabled(SpecId::LATEST)); + assert!(BedrockSpec::enabled(SpecId::BEDROCK)); + assert!(!BedrockSpec::enabled(SpecId::REGOLITH)); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_regolith_post_merge_hardforks() { + assert!(RegolithSpec::enabled(SpecId::MERGE)); + assert!(!RegolithSpec::enabled(SpecId::SHANGHAI)); + assert!(!RegolithSpec::enabled(SpecId::CANCUN)); + assert!(!RegolithSpec::enabled(SpecId::LATEST)); + assert!(RegolithSpec::enabled(SpecId::BEDROCK)); + assert!(RegolithSpec::enabled(SpecId::REGOLITH)); + } +} diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 42ba9f06c5..23c2bf736d 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -94,3 +94,32 @@ impl L1BlockInfo { .unwrap_or_default() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::primitives::specification::*; + + #[test] + fn test_data_gas() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000_000), + l1_fee_overhead: U256::from(1_000_000), + l1_fee_scalar: U256::from(1_000_000), + }; + + // 0xFACADE = 6 nibbles = 3 bytes + // 1111 1010 | 1100 1010 | 1101 1110 + // 111110101100101011011110 + // + // gas cost = 3 non-zero bytes * NON_ZERO_BYTE_COST + // gas cost += NON_ZERO_BYTE_COST * 68 + + let input = Bytes::from(hex!("FACADE").to_vec()); + let bedrock_data_gas = l1_block_info.data_gas::(&input); + assert_eq!(bedrock_data_gas, U256::from(1136)); + + let regolith_data_gas = l1_block_info.data_gas::(&input); + assert_eq!(regolith_data_gas, U256::from(48)); + } +} From af654a3377846a05460b4e03cb9760f01d6095e9 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 18:15:16 -0400 Subject: [PATCH 23/55] data gas tests --- crates/revm/src/optimism.rs | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 23c2bf736d..cf216583b9 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -101,7 +101,7 @@ mod tests { use crate::primitives::specification::*; #[test] - fn test_data_gas() { + fn test_data_gas_non_zero_bytes() { let l1_block_info = L1BlockInfo { l1_base_fee: U256::from(1_000_000), l1_fee_overhead: U256::from(1_000_000), @@ -109,17 +109,42 @@ mod tests { }; // 0xFACADE = 6 nibbles = 3 bytes - // 1111 1010 | 1100 1010 | 1101 1110 - // 111110101100101011011110 - // - // gas cost = 3 non-zero bytes * NON_ZERO_BYTE_COST - // gas cost += NON_ZERO_BYTE_COST * 68 + // 0xFACADE = 1111 1010 . 1100 1010 . 1101 1110 + // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes + // gas cost = 3 non-zero bytes * NON_ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 + // gas cost = 3 * 16 + 68 * 16 = 1136 let input = Bytes::from(hex!("FACADE").to_vec()); let bedrock_data_gas = l1_block_info.data_gas::(&input); assert_eq!(bedrock_data_gas, U256::from(1136)); + // Regolith has no added 68 non zero bytes + // gas cost = 3 * 16 = 48 let regolith_data_gas = l1_block_info.data_gas::(&input); assert_eq!(regolith_data_gas, U256::from(48)); } + + #[test] + fn test_data_gas_zero_bytes() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000_000), + l1_fee_overhead: U256::from(1_000_000), + l1_fee_scalar: U256::from(1_000_000), + }; + + // 0xFA00CA00DE = 10 nibbles = 5 bytes + // 0xFA00CA00DE = 1111 1010 . 0000 0000 . 1100 1010 . 0000 0000 . 1101 1110 + + // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes + // gas cost = 3 non-zero * NON_ZERO_BYTE_COST + 2 * ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 + // gas cost = 3 * 16 + 2 * 4 + 68 * 16 = 1144 + let input = Bytes::from(hex!("FA00CA00DE").to_vec()); + let bedrock_data_gas = l1_block_info.data_gas::(&input); + assert_eq!(bedrock_data_gas, U256::from(1144)); + + // Regolith has no added 68 non zero bytes + // gas cost = 3 * 16 + 2 * 4 = 56 + let regolith_data_gas = l1_block_info.data_gas::(&input); + assert_eq!(regolith_data_gas, U256::from(56)); + } } From e60a4d527a54fc714dd3d4ab0fbfffc523735512 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 18:19:33 -0400 Subject: [PATCH 24/55] calculate tx l1 cost test --- crates/revm/src/optimism.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index cf216583b9..a9f1b508f2 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -147,4 +147,21 @@ mod tests { let regolith_data_gas = l1_block_info.data_gas::(&input); assert_eq!(regolith_data_gas, U256::from(56)); } + + #[test] + fn test_calculate_tx_l1_cost() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: U256::from(1_000), + l1_fee_scalar: U256::from(1_000), + }; + + // The gas cost here should be zero since the tx is a deposit + let input = Bytes::from(hex!("FACADE").to_vec()); + let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, true); + assert_eq!(gas_cost, U256::ZERO); + + let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, false); + assert_eq!(gas_cost, U256::from(1048)); + } } From fa8b4e0a2b414d753211ff483e018e74f47c264d Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 18:22:46 -0400 Subject: [PATCH 25/55] Add a zero rollup data gas cost check --- crates/revm/src/optimism.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index a9f1b508f2..a5c85eea16 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -163,5 +163,10 @@ mod tests { let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, false); assert_eq!(gas_cost, U256::from(1048)); + + // Zero rollup data gas cost should result in zero for non-deposits + let input = Bytes::from(hex!("").to_vec()); + let gas_cost = l1_block_info.calculate_tx_l1_cost::(&input, false); + assert_eq!(gas_cost, U256::ZERO); } } From f0d7ad6ea26b915c49afea39cb07c0a765173f1e Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 18:31:56 -0400 Subject: [PATCH 26/55] Fix suggestions --- crates/primitives/src/specification.rs | 28 ++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/crates/primitives/src/specification.rs b/crates/primitives/src/specification.rs index f5858ca617..86f3a0f7b6 100644 --- a/crates/primitives/src/specification.rs +++ b/crates/primitives/src/specification.rs @@ -77,20 +77,19 @@ pub trait Spec: Sized { #[inline(always)] fn enabled(spec_id: SpecId) -> bool { - // If the Spec is Bedrock or Regolith, and the input is not Bedrock or Regolith, - // then no hardforks should be enabled after the merge. - let is_self_optimism = - Self::SPEC_ID == SpecId::BEDROCK || Self::SPEC_ID == SpecId::REGOLITH; - let input_not_optimism = spec_id != SpecId::BEDROCK && spec_id != SpecId::REGOLITH; - let after_merge = spec_id > SpecId::MERGE; - - // Optimism's Bedrock and Regolith hardforks implement changes on top of the Merge - // hardfork. This function is modified to preserve the original behavior of the - // spec IDs without having to put hardforks past Merge under - // `#[cfg(not(feature = "optimism"))]`. #[cfg(feature = "optimism")] - if is_self_optimism && input_not_optimism && after_merge { - return false; + { + // If the Spec is Bedrock or Regolith, and the input is not Bedrock or Regolith, + // then no hardforks should be enabled after the merge. This is because Optimism's + // Bedrock and Regolith hardforks implement changes on top of the Merge hardfork. + let is_self_optimism = + Self::SPEC_ID == SpecId::BEDROCK || Self::SPEC_ID == SpecId::REGOLITH; + let input_not_optimism = spec_id != SpecId::BEDROCK && spec_id != SpecId::REGOLITH; + let after_merge = spec_id > SpecId::MERGE; + + if is_self_optimism && input_not_optimism && after_merge { + return false; + } } Self::SPEC_ID as u8 >= spec_id as u8 @@ -134,11 +133,11 @@ spec!(BEDROCK, BedrockSpec); #[cfg(feature = "optimism")] spec!(REGOLITH, RegolithSpec); +#[cfg(feature = "optimism")] #[cfg(test)] mod tests { use super::*; - #[cfg(feature = "optimism")] #[test] fn test_bedrock_post_merge_hardforks() { assert!(BedrockSpec::enabled(SpecId::MERGE)); @@ -149,7 +148,6 @@ mod tests { assert!(!BedrockSpec::enabled(SpecId::REGOLITH)); } - #[cfg(feature = "optimism")] #[test] fn test_regolith_post_merge_hardforks() { assert!(RegolithSpec::enabled(SpecId::MERGE)); From d193011e8b59ebd50635bd6a5813d5da1828f28e Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 19:18:44 -0400 Subject: [PATCH 27/55] Bump the account nonce post-regolith for contract creation --- crates/revm/src/evm_impl.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index dcd778b4b7..1abb24a490 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -22,6 +22,8 @@ use revm_precompile::{Precompile, Precompiles}; #[cfg(feature = "optimism")] use crate::optimism; #[cfg(feature = "optimism")] +use crate::primitives::specification::RegolithSpec; +#[cfg(feature = "optimism")] use core::ops::Mul; pub struct EVMData<'a, DB: Database> { @@ -409,7 +411,26 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact Output::Create(return_value, _) => return_value, }, }, - SuccessOrHalt::Halt(reason) => ExecutionResult::Halt { reason, gas_used }, + SuccessOrHalt::Halt(reason) => { + // Post-regolith, if the transaction is a deposit transaction and the + // output is a contract creation, increment the account nonce even if + // the transaction halts. + #[cfg(feature = "optimism")] + { + let is_creation = matches!(output, Output::Create(_, _)); + let regolith_enabled = RegolithSpec::enabled(self.data.env.cfg.spec_id); + let optimism_regolith = self.data.env.cfg.optimism && regolith_enabled; + if is_deposit && is_creation && optimism_regolith { + let (acc, _) = self + .data + .journaled_state + .load_account(tx_caller, self.data.db) + .map_err(EVMError::Database)?; + acc.info.nonce = acc.info.nonce.checked_add(1).unwrap_or(u64::MAX); + } + } + ExecutionResult::Halt { reason, gas_used } + } SuccessOrHalt::FatalExternalError => { return Err(EVMError::Database(self.data.error.take().unwrap())); } From 710c6edb492e9a4666c355eb8f1237257b5c55ee Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 20:19:39 -0400 Subject: [PATCH 28/55] Add tx validation tests --- crates/primitives/src/env.rs | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 6001e8162c..4a27388476 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -418,3 +418,56 @@ impl Env { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "optimism")] + #[test] + fn test_validate_sys_tx() { + // Set the optimism flag to true and mark + // the tx as a system transaction. + let mut env = Env::default(); + env.cfg.optimism = true; + env.tx.optimism.is_system_transaction = Some(true); + assert_eq!( + env.validate_tx::(), + Err(InvalidTransaction::DepositSystemTxPostRegolith) + ); + + // Pre-regolith system transactions should be allowed. + assert!(env.validate_tx::().is_ok()); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_validate_deposit_tx() { + // Set the optimism flag and source hash. + let mut env = Env::default(); + env.cfg.optimism = true; + env.tx.optimism.source_hash = Some(B256::zero()); + assert_eq!(env.validate_tx::(), Ok(())); + } + + #[test] + fn test_validate_tx_chain_id() { + let mut env = Env::default(); + env.tx.chain_id = Some(1); + env.cfg.chain_id = U256::from(2); + assert_eq!( + env.validate_tx::(), + Err(InvalidTransaction::InvalidChainId) + ); + } + + #[test] + fn test_validate_tx_access_list() { + let mut env = Env::default(); + env.tx.access_list = vec![(B160::zero(), vec![])]; + assert_eq!( + env.validate_tx::(), + Err(InvalidTransaction::AccessListNotSupported) + ); + } +} From 988d6400b855f3e29757309c76a5eaba7bad2053 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 20:26:00 -0400 Subject: [PATCH 29/55] Add a deposit tx test --- crates/primitives/src/env.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 4a27388476..c1b65d0dde 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -447,7 +447,19 @@ mod tests { let mut env = Env::default(); env.cfg.optimism = true; env.tx.optimism.source_hash = Some(B256::zero()); - assert_eq!(env.validate_tx::(), Ok(())); + assert!(env.validate_tx::().is_ok()); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_validate_tx_against_state_deposit_tx() { + // Set the optimism flag and source hash. + let mut env = Env::default(); + env.cfg.optimism = true; + env.tx.optimism.source_hash = Some(B256::zero()); + + // Nonce and balance checks should be skipped for deposit transactions. + assert!(env.validate_tx_against_state(&Account::default()).is_ok()); } #[test] From f7a3373d0fc1be1fb8f5dd93da60494bc77d860c Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 21:08:52 -0400 Subject: [PATCH 30/55] Add gas tests --- crates/interpreter/src/gas.rs | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index acc424f900..c205f0540c 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -193,3 +193,89 @@ impl Gas { self.record_refund(refund); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(not(feature = "optimism"))] + #[test] + fn test_revert_gas() { + let mut gas = Gas::new(100); + gas.record_cost(50); + assert_eq!(gas.remaining(), 50); + assert_eq!(gas.used, 50); + assert_eq!(gas.all_used_gas, 50); + + // Consume the revert gas + gas.consume_revert_gas(Gas::new(50)); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.used, 0); + assert_eq!(gas.all_used_gas, 0); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_revert_gas() { + let mut gas = Gas::new(100); + gas.record_cost(50); + + gas.consume_revert_gas(true, false, false, Gas::new(50)); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.used, 0); + assert_eq!(gas.all_used_gas, 0); + + let mut gas = Gas::new(100); + gas.consume_revert_gas(false, false, false, Gas::new(50)); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_revert_gas_non_optimism() { + let mut gas = Gas::new(100); + gas.consume_revert_gas(false, false, false, Gas::new(50)); + assert_eq!(gas.remaining(), 100); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_consume_gas() { + let mut gas = Gas::new(100); + gas.record_cost(50); + + gas.consume_gas(true, true, true, None, 100, Gas::new(50)); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.used, 0); + assert_eq!(gas.all_used_gas, 0); + assert_eq!(gas.refunded, 0); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_consume_gas_with_refund() { + let mut gas = Gas::new(100); + gas.record_cost(50); + + let mut ret_gas = Gas::new(50); + ret_gas.record_refund(50); + gas.consume_gas(true, true, true, None, 100, ret_gas); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.used, 0); + assert_eq!(gas.all_used_gas, 0); + assert_eq!(gas.refunded, 50); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_consume_gas_sys_deposit_tx() { + let mut gas = Gas::new(100); + gas.record_cost(100); + gas.consume_gas(true, true, false, Some(true), 50, Gas::new(0)); + assert_eq!(gas.remaining(), 50); + assert_eq!(gas.used, 50); + assert_eq!(gas.all_used_gas, 50); + + gas.consume_gas(true, true, false, Some(true), 50, Gas::new(0)); + assert_eq!(gas, Gas::new(100)); + } +} From b31029eb00c3cabf06a1f2295c503aa0da353a70 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 21:14:52 -0400 Subject: [PATCH 31/55] Add gas tests --- crates/interpreter/src/gas.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index c205f0540c..2e7e32386a 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -198,6 +198,39 @@ impl Gas { mod tests { use super::*; + #[cfg(not(feature = "optimism"))] + #[test] + fn test_consume_gas() { + let mut gas = Gas::new(100); + gas.record_cost(50); + assert_eq!(gas.remaining(), 50); + assert_eq!(gas.used, 50); + assert_eq!(gas.all_used_gas, 50); + + // Consume the revert gas + gas.consume_gas(Gas::new(50)); + assert_eq!(gas, Gas::new(100)); + } + + #[cfg(not(feature = "optimism"))] + #[test] + fn test_consume_gas_with_refund() { + let mut gas = Gas::new(100); + gas.record_cost(50); + assert_eq!(gas.remaining(), 50); + assert_eq!(gas.used, 50); + assert_eq!(gas.all_used_gas, 50); + + // Consume the revert gas + let mut ret_gas = Gas::new(50); + ret_gas.record_refund(50); + gas.consume_gas(ret_gas); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.used, 0); + assert_eq!(gas.all_used_gas, 0); + assert_eq!(gas.refunded, 50); + } + #[cfg(not(feature = "optimism"))] #[test] fn test_revert_gas() { From a0cc0700060e279687698717d1db6b2b14d6930c Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Thu, 7 Sep 2023 15:10:55 -0400 Subject: [PATCH 32/55] Fix regolith check --- crates/revm/src/evm_impl.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 1abb24a490..e62a12547f 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -22,8 +22,6 @@ use revm_precompile::{Precompile, Precompiles}; #[cfg(feature = "optimism")] use crate::optimism; #[cfg(feature = "optimism")] -use crate::primitives::specification::RegolithSpec; -#[cfg(feature = "optimism")] use core::ops::Mul; pub struct EVMData<'a, DB: Database> { @@ -418,7 +416,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact #[cfg(feature = "optimism")] { let is_creation = matches!(output, Output::Create(_, _)); - let regolith_enabled = RegolithSpec::enabled(self.data.env.cfg.spec_id); + let regolith_enabled = GSPEC::enabled(SpecId::REGOLITH); let optimism_regolith = self.data.env.cfg.optimism && regolith_enabled; if is_deposit && is_creation && optimism_regolith { let (acc, _) = self From b1634195f89eba7930fee8db3e3fac7867fd4e0e Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Thu, 7 Sep 2023 15:33:17 -0400 Subject: [PATCH 33/55] Fix func ordering --- crates/interpreter/src/gas.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index 2e7e32386a..69dadf94f0 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -93,14 +93,6 @@ impl Gas { true } - /// Consumes the remaining gas. - #[cfg(not(feature = "optimism"))] - #[inline] - pub fn consume_gas(&mut self, ret_gas: Gas) { - self.erase_cost(ret_gas.remaining()); - self.record_refund(ret_gas.refunded()); - } - /// Consume the revert gas. #[cfg(not(feature = "optimism"))] #[inline] @@ -135,6 +127,14 @@ impl Gas { } } + /// Consumes the remaining gas. + #[cfg(not(feature = "optimism"))] + #[inline] + pub fn consume_gas(&mut self, ret_gas: Gas) { + self.erase_cost(ret_gas.remaining()); + self.record_refund(ret_gas.refunded()); + } + /// Consume remaining gas. #[cfg(feature = "optimism")] #[inline] From 23373aea4d5c59b53242f8f0b51adf12e94d33c5 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Thu, 7 Sep 2023 15:49:13 -0400 Subject: [PATCH 34/55] Fix test --- crates/primitives/src/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 0829ef155d..b044717e6e 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -466,7 +466,7 @@ mod tests { fn test_validate_tx_chain_id() { let mut env = Env::default(); env.tx.chain_id = Some(1); - env.cfg.chain_id = U256::from(2); + env.cfg.chain_id = 2; assert_eq!( env.validate_tx::(), Err(InvalidTransaction::InvalidChainId) From 531aca09d642c9a47d867ed336fc2f8fad6c45ac Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Thu, 7 Sep 2023 17:21:35 -0400 Subject: [PATCH 35/55] Swap the l1_cost to use the raw enveloped tx --- crates/primitives/src/env.rs | 6 ++- crates/revm/src/evm_impl.rs | 78 ++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index b044717e6e..afa27b4fec 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -36,7 +36,11 @@ pub struct OptimismFields { pub source_hash: Option, pub mint: Option, pub is_system_transaction: Option, - pub l1_cost: Option, + /// An enveloped EIP-2718 typed transaction. This is used + /// to compute the l1 tx cost using the l1 block info, as + /// opposed to requiring downstream apps to compute the cost + /// externally. + pub enveloped_tx: Bytes, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index f0e26f7a6c..dc724eb6d2 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -98,34 +98,32 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, fn remove_l1_cost( is_deposit: bool, tx_caller: B160, - tx_l1_cost: Option, + l1_cost: U256, db: &mut DB, journal: &mut JournaledState, ) -> Result<(), EVMError> { if is_deposit { return Ok(()); } - if let Some(l1_cost) = tx_l1_cost { - let acc = journal - .load_account(tx_caller, db) - .map_err(EVMError::Database)? - .0; - if l1_cost.gt(&acc.info.balance) { - let x = l1_cost.as_limbs(); - let u64_cost = if x[1] == 0 && x[2] == 0 && x[3] == 0 { - x[0] - } else { - u64::MAX - }; - return Err(EVMError::Transaction( - InvalidTransaction::LackOfFundForMaxFee { - fee: u64_cost, - balance: acc.info.balance, - }, - )); - } - acc.info.balance = acc.info.balance.saturating_sub(l1_cost); + let acc = journal + .load_account(tx_caller, db) + .map_err(EVMError::Database)? + .0; + if l1_cost.gt(&acc.info.balance) { + let x = l1_cost.as_limbs(); + let u64_cost = if x[1] == 0 && x[2] == 0 && x[3] == 0 { + x[0] + } else { + u64::MAX + }; + return Err(EVMError::Transaction( + InvalidTransaction::LackOfFundForMaxFee { + fee: u64_cost, + balance: acc.info.balance, + }, + )); } + acc.info.balance = acc.info.balance.saturating_sub(l1_cost); Ok(()) } @@ -193,13 +191,20 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] - let (tx_mint, tx_system, tx_l1_cost, is_deposit) = ( + let (tx_mint, tx_system, is_deposit) = ( env.tx.optimism.mint, env.tx.optimism.is_system_transaction, - env.tx.optimism.l1_cost, env.tx.optimism.source_hash.is_some(), ); + // Perform this calculation optimistically to avoid cloning the enveloped tx. + #[cfg(feature = "optimism")] + let tx_l1_cost = { + let l1_block_info = + optimism::L1BlockInfo::try_fetch(&mut self.data.db).map_err(EVMError::Database)?; + l1_block_info.calculate_tx_l1_cost::(&env.tx.optimism.enveloped_tx, is_deposit) + }; + let initial_gas_spend = initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); @@ -481,18 +486,21 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, panic!("[OPTIMISM] Failed to load L1 block information."); }; - // Send the L1 cost of the transaction to the L1 Fee Vault. - if let Some(l1_cost) = self.data.env.tx.optimism.l1_cost { - let Ok((l1_fee_vault_account, _)) = self - .data - .journaled_state - .load_account(optimism::L1_FEE_RECIPIENT, self.data.db) - else { - panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); - }; - l1_fee_vault_account.mark_touch(); - l1_fee_vault_account.info.balance += l1_cost; - } + let l1_cost = l1_block_info.calculate_tx_l1_cost::( + &self.data.env.tx.optimism.enveloped_tx, + is_deposit, + ); + + // Send the L1 cost of the transaction to the L1 Fee Vault. if let Some(l1_cost) = self.data.env.tx.optimism.l1_cost { + let Ok((l1_fee_vault_account, _)) = self + .data + .journaled_state + .load_account(optimism::L1_FEE_RECIPIENT, self.data.db) + else { + panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); + }; + l1_fee_vault_account.mark_touch(); + l1_fee_vault_account.info.balance += l1_cost; // Send the base fee of the transaction to the Base Fee Vault. let Ok((base_fee_vault_account, _)) = self From bdc334ec0045f326bf966413ee80bb5ce2369c2c Mon Sep 17 00:00:00 2001 From: "refcell.eth" Date: Thu, 7 Sep 2023 17:58:15 -0400 Subject: [PATCH 36/55] Update crates/revm/src/evm_impl.rs Co-authored-by: clabby --- crates/revm/src/evm_impl.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index dc724eb6d2..ec44a436df 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -111,10 +111,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, .0; if l1_cost.gt(&acc.info.balance) { let x = l1_cost.as_limbs(); - let u64_cost = if x[1] == 0 && x[2] == 0 && x[3] == 0 { - x[0] - } else { + let u64_cost = if U256::from(u64::MAX).lt(&l1_cost) { u64::MAX + } else { + l1_cost.as_limbs()[0] }; return Err(EVMError::Transaction( InvalidTransaction::LackOfFundForMaxFee { From a92bb4f8de91f21c829d63311fa5d95579b57a1b Mon Sep 17 00:00:00 2001 From: "refcell.eth" Date: Thu, 7 Sep 2023 17:58:36 -0400 Subject: [PATCH 37/55] Update crates/revm/src/evm_impl.rs Co-authored-by: clabby --- crates/revm/src/evm_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index ec44a436df..a033f216d6 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -491,7 +491,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, is_deposit, ); - // Send the L1 cost of the transaction to the L1 Fee Vault. if let Some(l1_cost) = self.data.env.tx.optimism.l1_cost { + // Send the L1 cost of the transaction to the L1 Fee Vault. let Ok((l1_fee_vault_account, _)) = self .data .journaled_state From 21d907d223996a782487118cd05e7a19a9e604f4 Mon Sep 17 00:00:00 2001 From: "refcell.eth" Date: Thu, 7 Sep 2023 17:58:44 -0400 Subject: [PATCH 38/55] Update crates/primitives/src/env.rs Co-authored-by: clabby --- crates/primitives/src/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index afa27b4fec..f9ae403d54 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -37,7 +37,7 @@ pub struct OptimismFields { pub mint: Option, pub is_system_transaction: Option, /// An enveloped EIP-2718 typed transaction. This is used - /// to compute the l1 tx cost using the l1 block info, as + /// to compute the L1 tx cost using the L1 block info, as /// opposed to requiring downstream apps to compute the cost /// externally. pub enveloped_tx: Bytes, From 27760ca53ffe61bedd3b78fc445e5e24b199e30d Mon Sep 17 00:00:00 2001 From: clabby Date: Thu, 7 Sep 2023 18:00:29 -0400 Subject: [PATCH 39/55] Make clippy happy --- crates/revm/src/evm_impl.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index a033f216d6..3c0587b0c6 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -110,7 +110,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, .map_err(EVMError::Database)? .0; if l1_cost.gt(&acc.info.balance) { - let x = l1_cost.as_limbs(); let u64_cost = if U256::from(u64::MAX).lt(&l1_cost) { u64::MAX } else { From 0d4ccb5870507a99c9b62485d62fae5f47dc3fac Mon Sep 17 00:00:00 2001 From: clabby Date: Thu, 7 Sep 2023 19:34:04 -0400 Subject: [PATCH 40/55] perf: Only load `L1BlockInfo` once --- crates/revm/src/evm_impl.rs | 45 ++++++++++++++++++++++++----------- crates/revm/src/optimism.rs | 47 ++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 3c0587b0c6..3c7bd6b691 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -190,18 +190,25 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] - let (tx_mint, tx_system, is_deposit) = ( - env.tx.optimism.mint, - env.tx.optimism.is_system_transaction, - env.tx.optimism.source_hash.is_some(), - ); + let (tx_mint, tx_system, tx_l1_cost, is_deposit, l1_block_info) = { + let is_deposit = env.tx.optimism.source_hash.is_some(); - // Perform this calculation optimistically to avoid cloning the enveloped tx. - #[cfg(feature = "optimism")] - let tx_l1_cost = { let l1_block_info = - optimism::L1BlockInfo::try_fetch(&mut self.data.db).map_err(EVMError::Database)?; - l1_block_info.calculate_tx_l1_cost::(&env.tx.optimism.enveloped_tx, is_deposit) + optimism::L1BlockInfo::try_fetch_mut(self.data.db, self.data.env.cfg.optimism)?; + + // Perform this calculation optimistically to avoid cloning the enveloped tx. + let tx_l1_cost = l1_block_info.clone().map(|l1_block_info| { + l1_block_info + .calculate_tx_l1_cost::(&env.tx.optimism.enveloped_tx, is_deposit) + }); + + ( + env.tx.optimism.mint, + env.tx.optimism.is_system_transaction, + tx_l1_cost, + is_deposit, + l1_block_info, + ) }; let initial_gas_spend = @@ -229,6 +236,9 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact journal, )?; + let Some(tx_l1_cost) = tx_l1_cost else { + panic!("[OPTIMISM] L1 Block Info could not be loaded from the DB.") + }; EVMImpl::::remove_l1_cost( is_deposit, tx_caller, @@ -328,7 +338,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact } } - let (state, logs, gas_used, gas_refunded) = self.finalize::(&gas); + let (state, logs, gas_used, gas_refunded) = self.finalize::( + &gas, + #[cfg(feature = "optimism")] + l1_block_info.as_ref(), + ); let result = match exit_reason.into() { SuccessOrHalt::Success(reason) => ExecutionResult::Success { @@ -407,7 +421,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } } - fn finalize(&mut self, gas: &Gas) -> (HashMap, Vec, u64, u64) { + fn finalize( + &mut self, + gas: &Gas, + #[cfg(feature = "optimism")] l1_block_info: Option<&optimism::L1BlockInfo>, + ) -> (HashMap, Vec, u64, u64) { let caller = self.data.env.tx.caller; let coinbase = self.data.env.block.coinbase; let (gas_used, gas_refunded) = if crate::USE_GAS { @@ -480,8 +498,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, if self.data.env.cfg.optimism && !is_deposit { // If the transaction is not a deposit transaction, fees are paid out // to both the Base Fee Vault as well as the L1 Fee Vault. - - let Ok(l1_block_info) = optimism::L1BlockInfo::try_fetch(&mut self.data.db) else { + let Some(l1_block_info) = l1_block_info else { panic!("[OPTIMISM] Failed to load L1 block information."); }; diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index a5c85eea16..946d8a00f0 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -2,7 +2,9 @@ use core::ops::Mul; use revm_interpreter::primitives::{ - db::Database, hex_literal::hex, Bytes, Spec, SpecId, B160, U256, + db::{Database, DatabaseRef}, + hex_literal::hex, + Bytes, EVMError, Spec, SpecId, B160, U256, }; const ZERO_BYTE_COST: u64 = 4; @@ -43,17 +45,46 @@ pub struct L1BlockInfo { } impl L1BlockInfo { - /// Fetches the L1 block info from the `L1Block` contract in the database. - pub fn try_fetch(db: &mut DB) -> Result { - let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; - let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; - let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; + pub fn try_fetch_mut( + db: &mut DB, + is_optimism: bool, + ) -> Result, EVMError> { + let l1_base_fee = db + .storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT) + .map_err(EVMError::Database)?; + let l1_fee_overhead = db + .storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT) + .map_err(EVMError::Database)?; + let l1_fee_scalar = db + .storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT) + .map_err(EVMError::Database)?; + + Ok(is_optimism.then_some(L1BlockInfo { + l1_base_fee, + l1_fee_overhead, + l1_fee_scalar, + })) + } - Ok(L1BlockInfo { + pub fn try_fetch( + db: &DB, + is_optimism: bool, + ) -> Result, EVMError> { + let l1_base_fee = db + .storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT) + .map_err(EVMError::Database)?; + let l1_fee_overhead = db + .storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT) + .map_err(EVMError::Database)?; + let l1_fee_scalar = db + .storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT) + .map_err(EVMError::Database)?; + + Ok(is_optimism.then_some(L1BlockInfo { l1_base_fee, l1_fee_overhead, l1_fee_scalar, - }) + })) } /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero From bb9acfec686b27446e5660c180f19182fcb97045 Mon Sep 17 00:00:00 2001 From: clabby Date: Thu, 7 Sep 2023 19:36:16 -0400 Subject: [PATCH 41/55] Remove extra `try_fetch` fn --- crates/revm/src/evm_impl.rs | 2 +- crates/revm/src/optimism.rs | 27 ++------------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 3c7bd6b691..5e4449f5a5 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -194,7 +194,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let is_deposit = env.tx.optimism.source_hash.is_some(); let l1_block_info = - optimism::L1BlockInfo::try_fetch_mut(self.data.db, self.data.env.cfg.optimism)?; + optimism::L1BlockInfo::try_fetch(self.data.db, self.data.env.cfg.optimism)?; // Perform this calculation optimistically to avoid cloning the enveloped tx. let tx_l1_cost = l1_block_info.clone().map(|l1_block_info| { diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 946d8a00f0..c1e036b02b 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -2,9 +2,7 @@ use core::ops::Mul; use revm_interpreter::primitives::{ - db::{Database, DatabaseRef}, - hex_literal::hex, - Bytes, EVMError, Spec, SpecId, B160, U256, + db::Database, hex_literal::hex, Bytes, EVMError, Spec, SpecId, B160, U256, }; const ZERO_BYTE_COST: u64 = 4; @@ -45,7 +43,7 @@ pub struct L1BlockInfo { } impl L1BlockInfo { - pub fn try_fetch_mut( + pub fn try_fetch( db: &mut DB, is_optimism: bool, ) -> Result, EVMError> { @@ -66,27 +64,6 @@ impl L1BlockInfo { })) } - pub fn try_fetch( - db: &DB, - is_optimism: bool, - ) -> Result, EVMError> { - let l1_base_fee = db - .storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT) - .map_err(EVMError::Database)?; - let l1_fee_overhead = db - .storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT) - .map_err(EVMError::Database)?; - let l1_fee_scalar = db - .storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT) - .map_err(EVMError::Database)?; - - Ok(is_optimism.then_some(L1BlockInfo { - l1_base_fee, - l1_fee_overhead, - l1_fee_scalar, - })) - } - /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero /// byte and 4 gas per zero byte. /// From 3f9ca9db7f6761ac1bf679c785c41d4ed1aa9f32 Mon Sep 17 00:00:00 2001 From: clabby Date: Thu, 7 Sep 2023 19:46:55 -0400 Subject: [PATCH 42/55] perf: lazy `try_fetch` eval --- crates/revm/src/optimism.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index c1e036b02b..650ce56635 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -47,21 +47,25 @@ impl L1BlockInfo { db: &mut DB, is_optimism: bool, ) -> Result, EVMError> { - let l1_base_fee = db - .storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT) - .map_err(EVMError::Database)?; - let l1_fee_overhead = db - .storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT) - .map_err(EVMError::Database)?; - let l1_fee_scalar = db - .storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT) - .map_err(EVMError::Database)?; - - Ok(is_optimism.then_some(L1BlockInfo { - l1_base_fee, - l1_fee_overhead, - l1_fee_scalar, - })) + is_optimism + .then(|| { + let l1_base_fee = db + .storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT) + .map_err(EVMError::Database)?; + let l1_fee_overhead = db + .storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT) + .map_err(EVMError::Database)?; + let l1_fee_scalar = db + .storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT) + .map_err(EVMError::Database)?; + + Ok(L1BlockInfo { + l1_base_fee, + l1_fee_overhead, + l1_fee_scalar, + }) + }) + .map_or(Ok(None), |v| v.map(Some)) } /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per non-zero From 8fd3a3cd168c8e9a5b7018567bee06020c8bf00d Mon Sep 17 00:00:00 2001 From: clabby Date: Thu, 7 Sep 2023 20:05:52 -0400 Subject: [PATCH 43/55] andreas was right Co-Authored-By: Refcell --- crates/revm/src/evm_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 5e4449f5a5..cbc9f2db20 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -197,7 +197,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact optimism::L1BlockInfo::try_fetch(self.data.db, self.data.env.cfg.optimism)?; // Perform this calculation optimistically to avoid cloning the enveloped tx. - let tx_l1_cost = l1_block_info.clone().map(|l1_block_info| { + let tx_l1_cost = l1_block_info.as_ref().map(|l1_block_info| { l1_block_info .calculate_tx_l1_cost::(&env.tx.optimism.enveloped_tx, is_deposit) }); From 2c72f86a74c2a5595c9ac6116599d1f66a406e43 Mon Sep 17 00:00:00 2001 From: clabby Date: Thu, 7 Sep 2023 20:15:17 -0400 Subject: [PATCH 44/55] Improve error abstraction Co-Authored-By: Refcell --- crates/revm/src/evm_impl.rs | 3 ++- crates/revm/src/optimism.rs | 16 +++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index cbc9f2db20..450dca5123 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -194,7 +194,8 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let is_deposit = env.tx.optimism.source_hash.is_some(); let l1_block_info = - optimism::L1BlockInfo::try_fetch(self.data.db, self.data.env.cfg.optimism)?; + optimism::L1BlockInfo::try_fetch(self.data.db, self.data.env.cfg.optimism) + .map_err(EVMError::Database)?; // Perform this calculation optimistically to avoid cloning the enveloped tx. let tx_l1_cost = l1_block_info.as_ref().map(|l1_block_info| { diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs index 650ce56635..e33d1d8eff 100644 --- a/crates/revm/src/optimism.rs +++ b/crates/revm/src/optimism.rs @@ -2,7 +2,7 @@ use core::ops::Mul; use revm_interpreter::primitives::{ - db::Database, hex_literal::hex, Bytes, EVMError, Spec, SpecId, B160, U256, + db::Database, hex_literal::hex, Bytes, Spec, SpecId, B160, U256, }; const ZERO_BYTE_COST: u64 = 4; @@ -46,18 +46,12 @@ impl L1BlockInfo { pub fn try_fetch( db: &mut DB, is_optimism: bool, - ) -> Result, EVMError> { + ) -> Result, DB::Error> { is_optimism .then(|| { - let l1_base_fee = db - .storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT) - .map_err(EVMError::Database)?; - let l1_fee_overhead = db - .storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT) - .map_err(EVMError::Database)?; - let l1_fee_scalar = db - .storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT) - .map_err(EVMError::Database)?; + let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; + let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; Ok(L1BlockInfo { l1_base_fee, From 61b21a037f6bd846099bae44d62cee7d80b4dce4 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 22:16:29 -0400 Subject: [PATCH 45/55] EVM Impl Tests --- crates/revm/src/evm_impl.rs | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 450dca5123..d3bd625b06 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1122,3 +1122,59 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host } } } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::db::InMemoryDB; + use crate::primitives::specification::BedrockSpec; + use crate::primitives::state::AccountInfo; + + #[cfg(feature = "optimism")] + #[test] + fn test_commit_mint_value() { + let caller = B160::zero(); + let mint_value = Some(1u128); + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + nonce: 0, + balance: U256::from(100), + code_hash: B256::zero(), + code: None, + }, + ); + let mut journal = JournaledState::new(0); + journal + .initial_account_load(caller, &[U256::from(100)], &mut db) + .unwrap(); + assert!( + EVMImpl::::commit_mint_value( + caller, + mint_value, + &mut db, + &mut journal + ) + .is_ok(), + ); + + // Check the account balance is updated. + let (account, _) = journal.load_account(caller, &mut db).unwrap(); + assert_eq!(account.info.balance, U256::from(101)); + + // No mint value should be a no-op. + assert!( + EVMImpl::::commit_mint_value( + caller, + None, + &mut db, + &mut journal + ) + .is_ok(), + ); + let (account, _) = journal.load_account(caller, &mut db).unwrap(); + assert_eq!(account.info.balance, U256::from(101)); + } +} From 476f7f2ebbc7d321b8ad77fb5e70b1acdd9cfded Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 6 Sep 2023 22:34:25 -0400 Subject: [PATCH 46/55] More tests --- crates/revm/src/evm_impl.rs | 88 ++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index d3bd625b06..89cfae6345 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1123,6 +1123,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host } } +#[cfg(feature = "optimism")] #[cfg(test)] mod tests { use super::*; @@ -1131,7 +1132,6 @@ mod tests { use crate::primitives::specification::BedrockSpec; use crate::primitives::state::AccountInfo; - #[cfg(feature = "optimism")] #[test] fn test_commit_mint_value() { let caller = B160::zero(); @@ -1177,4 +1177,90 @@ mod tests { let (account, _) = journal.load_account(caller, &mut db).unwrap(); assert_eq!(account.info.balance, U256::from(101)); } + + #[test] + fn test_remove_l1_cost_non_deposit() { + let caller = B160::zero(); + let mut db = InMemoryDB::default(); + let mut journal = JournaledState::new(0); + let slots = &[U256::from(100)]; + journal + .initial_account_load(caller, slots, &mut db) + .unwrap(); + assert!(EVMImpl::::remove_l1_cost( + true, + caller, + None, + &mut db, + &mut journal + ) + .is_ok(),); + } + + #[test] + fn test_remove_l1_cost() { + let caller = B160::zero(); + let tx_l1_cost = Some(U256::from(1)); + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + nonce: 0, + balance: U256::from(100), + code_hash: B256::zero(), + code: None, + }, + ); + let mut journal = JournaledState::new(0); + journal + .initial_account_load(caller, &[U256::from(100)], &mut db) + .unwrap(); + assert!(EVMImpl::::remove_l1_cost( + false, + caller, + tx_l1_cost, + &mut db, + &mut journal + ) + .is_ok(),); + + // Check the account balance is updated. + let (account, _) = journal.load_account(caller, &mut db).unwrap(); + assert_eq!(account.info.balance, U256::from(99)); + } + + #[test] + fn test_remove_l1_cost_lack_of_funds() { + let caller = B160::zero(); + let tx_l1_cost = Some(U256::from(101)); + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + nonce: 0, + balance: U256::from(100), + code_hash: B256::zero(), + code: None, + }, + ); + let mut journal = JournaledState::new(0); + journal + .initial_account_load(caller, &[U256::from(100)], &mut db) + .unwrap(); + assert_eq!( + EVMImpl::::remove_l1_cost( + false, + caller, + tx_l1_cost, + &mut db, + &mut journal + ), + Err(EVMError::Transaction( + InvalidTransaction::LackOfFundForMaxFee { + fee: 101u64, + balance: U256::from(100), + }, + )) + ); + } } From e7a2440d463bd6148065679f67e5e4178d59049d Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Thu, 7 Sep 2023 20:25:05 -0400 Subject: [PATCH 47/55] Fix breaking changes --- crates/revm/src/evm_impl.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 89cfae6345..43c8036d27 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1190,7 +1190,7 @@ mod tests { assert!(EVMImpl::::remove_l1_cost( true, caller, - None, + U256::ZERO, &mut db, &mut journal ) @@ -1200,7 +1200,6 @@ mod tests { #[test] fn test_remove_l1_cost() { let caller = B160::zero(); - let tx_l1_cost = Some(U256::from(1)); let mut db = InMemoryDB::default(); db.insert_account_info( caller, @@ -1218,7 +1217,7 @@ mod tests { assert!(EVMImpl::::remove_l1_cost( false, caller, - tx_l1_cost, + U256::from(1), &mut db, &mut journal ) @@ -1232,7 +1231,6 @@ mod tests { #[test] fn test_remove_l1_cost_lack_of_funds() { let caller = B160::zero(); - let tx_l1_cost = Some(U256::from(101)); let mut db = InMemoryDB::default(); db.insert_account_info( caller, @@ -1251,7 +1249,7 @@ mod tests { EVMImpl::::remove_l1_cost( false, caller, - tx_l1_cost, + U256::from(101), &mut db, &mut journal ), From 2962e7a477abeaac537a46d05c90de3875b27522 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Fri, 8 Sep 2023 11:01:44 -0400 Subject: [PATCH 48/55] Update the enveloped tx to be optional. --- crates/primitives/src/env.rs | 5 ++++- crates/revm/src/evm_impl.rs | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index f9ae403d54..9d883f6b0f 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -40,7 +40,10 @@ pub struct OptimismFields { /// to compute the L1 tx cost using the L1 block info, as /// opposed to requiring downstream apps to compute the cost /// externally. - pub enveloped_tx: Bytes, + /// This field is optional to allow the [TxEnv] to be constructed + /// for non-optimism chains when the `optimism` feature is enabled, + /// but the [CfgEnv] `optimism` field is set to false. + pub enveloped_tx: Option, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 43c8036d27..1173bde099 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -199,8 +199,14 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // Perform this calculation optimistically to avoid cloning the enveloped tx. let tx_l1_cost = l1_block_info.as_ref().map(|l1_block_info| { - l1_block_info - .calculate_tx_l1_cost::(&env.tx.optimism.enveloped_tx, is_deposit) + env.tx + .optimism + .enveloped_tx + .as_ref() + .map(|enveloped_tx| { + l1_block_info.calculate_tx_l1_cost::(enveloped_tx, is_deposit) + }) + .unwrap_or(U256::ZERO) }); ( @@ -503,10 +509,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, panic!("[OPTIMISM] Failed to load L1 block information."); }; - let l1_cost = l1_block_info.calculate_tx_l1_cost::( - &self.data.env.tx.optimism.enveloped_tx, - is_deposit, - ); + let Some(enveloped_tx) = &self.data.env.tx.optimism.enveloped_tx else { + panic!("[OPTIMISM] Failed to load enveloped transaction."); + }; + + let l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx, is_deposit); // Send the L1 cost of the transaction to the L1 Fee Vault. let Ok((l1_fee_vault_account, _)) = self From c1d667f9822fd40d7c6d227c0cb4b67a7af6d25e Mon Sep 17 00:00:00 2001 From: clabby Date: Sat, 16 Sep 2023 12:25:34 -0400 Subject: [PATCH 49/55] Merge REVM upgrades --- .github/workflows/ci.yml | 5 + .github/workflows/ethereum-tests.yml | 15 +- .rustfmt.toml | 0 Cargo.lock | 178 +- Cargo.toml | 1 - README.md | 28 +- bins/revme/Cargo.toml | 2 +- bins/revme/src/cmd.rs | 16 +- bins/revme/src/exec.rs | 1 - bins/revme/src/main.rs | 7 +- bins/revme/src/parser.rs | 5 - bins/revme/src/runner/mod.rs | 4 - bins/revme/src/state.rs | 0 bins/revme/src/statetest/cmd.rs | 2 +- bins/revme/src/statetest/main.rs | 26 - bins/revme/src/statetest/models/mod.rs | 60 +- bins/revme/src/statetest/runner.rs | 474 +- book.toml | 3 +- crates/interpreter/src/instructions.rs | 1 + crates/interpreter/src/instructions/host.rs | 2 + .../interpreter/src/instructions/host_env.rs | 19 +- crates/interpreter/src/instructions/opcode.rs | 10 +- crates/precompile/Cargo.toml | 12 +- crates/precompile/src/kzg_point_evaluation.rs | 118 + crates/precompile/src/lib.rs | 53 +- crates/primitives/Cargo.toml | 11 +- crates/primitives/build.rs | 129 + crates/primitives/src/bits.rs | 2 +- crates/primitives/src/bytecode.rs | 11 +- crates/primitives/src/constants.rs | 12 + crates/primitives/src/env.rs | 231 +- crates/primitives/src/kzg.rs | 9 + crates/primitives/src/kzg/env_settings.rs | 36 + crates/primitives/src/kzg/g1_points.bin | Bin 0 -> 196608 bytes crates/primitives/src/kzg/g2_points.bin | Bin 0 -> 6240 bytes crates/primitives/src/kzg/generated.rs | 24 + crates/primitives/src/kzg/trusted_setup.txt | 4163 +++++++++++++++++ crates/primitives/src/kzg/trusted_setup_4.txt | 71 + crates/primitives/src/lib.rs | 22 +- crates/primitives/src/precompile.rs | 12 +- crates/primitives/src/result.rs | 28 +- crates/primitives/src/specification.rs | 101 +- crates/primitives/src/utilities.rs | 148 +- crates/revm/Cargo.toml | 10 +- crates/revm/src/db.rs | 18 +- crates/revm/src/db/in_memory_db.rs | 4 +- crates/revm/src/db/states/bundle_account.rs | 3 +- crates/revm/src/db/states/bundle_state.rs | 30 +- crates/revm/src/db/states/cache.rs | 2 + crates/revm/src/db/states/changes.rs | 25 +- crates/revm/src/db/states/reverts.rs | 8 +- crates/revm/src/db/states/state.rs | 20 +- crates/revm/src/db/states/transition_state.rs | 1 + crates/revm/src/evm_impl.rs | 82 +- crates/revm/src/inspector/tracer_eip3155.rs | 1 - documentation/src/SUMMARY.md | 1 + documentation/src/crates/interpreter.md | 10 +- documentation/src/crates/precompile.md | 8 +- .../src/crates/precompile/point_evaluation.md | 2 +- documentation/src/crates/revm/evm_impl.md | 65 +- documentation/src/crates/revm/host_trait.md | 57 + .../src/crates/revm/journaled_state.md | 19 +- documentation/src/introduction.md | 4 +- 63 files changed, 5804 insertions(+), 618 deletions(-) delete mode 100644 .rustfmt.toml delete mode 100644 bins/revme/src/exec.rs delete mode 100644 bins/revme/src/parser.rs delete mode 100644 bins/revme/src/runner/mod.rs delete mode 100644 bins/revme/src/state.rs delete mode 100644 bins/revme/src/statetest/main.rs create mode 100644 crates/precompile/src/kzg_point_evaluation.rs create mode 100644 crates/primitives/build.rs create mode 100644 crates/primitives/src/kzg.rs create mode 100644 crates/primitives/src/kzg/env_settings.rs create mode 100644 crates/primitives/src/kzg/g1_points.bin create mode 100644 crates/primitives/src/kzg/g2_points.bin create mode 100644 crates/primitives/src/kzg/generated.rs create mode 100644 crates/primitives/src/kzg/trusted_setup.txt create mode 100644 crates/primitives/src/kzg/trusted_setup_4.txt create mode 100644 documentation/src/crates/revm/host_trait.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12654158ac..b67c05895b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,8 @@ jobs: - name: Install toolchain uses: dtolnay/rust-toolchain@stable + with: + targets: riscv32imac-unknown-none-elf - uses: Swatinem/rust-cache@v2 with: @@ -24,6 +26,9 @@ jobs: - name: cargo test run: cargo test --workspace --all-features + + - name: cargo check no_std + run: cargo check --target riscv32imac-unknown-none-elf --no-default-features lint: name: Lint diff --git a/.github/workflows/ethereum-tests.yml b/.github/workflows/ethereum-tests.yml index 9a8814ae2a..02a0863282 100644 --- a/.github/workflows/ethereum-tests.yml +++ b/.github/workflows/ethereum-tests.yml @@ -11,6 +11,9 @@ jobs: name: Ethereum Tests (Stable) runs-on: ubuntu-latest timeout-minutes: 30 + strategy: + matrix: + profile: [ethtests, release] steps: - name: Checkout sources uses: actions/checkout@v3 @@ -31,9 +34,9 @@ jobs: - name: Run Ethereum tests run: | - cargo run --profile ethtests -p revme -- \ - statetest \ - ethtests/GeneralStateTests/ \ - ethtests/LegacyTests/Constantinople/GeneralStateTests/ \ - tests/EIPTests/StateTests/stEIP5656-MCOPY/ \ - tests/EIPTests/StateTests/stEIP1153-transientStorage/ + cargo run --profile ${{ matrix.profile }} -p revme -- statetest \ + ethtests/GeneralStateTests/ \ + ethtests/LegacyTests/Constantinople/GeneralStateTests/ \ + ethtests/EIPTests/StateTests/stEIP1153-transientStorage/ \ + ethtests/EIPTests/StateTests/stEIP4844-blobtransactions/ \ + ethtests/EIPTests/StateTests/stEIP5656-MCOPY/ diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Cargo.lock b/Cargo.lock index e1d952b817..e97d376edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -325,6 +325,29 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.0", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.28", + "which", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -378,6 +401,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -398,13 +433,26 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ "serde", ] +[[package]] +name = "c-kzg" +version = "0.1.0" +source = "git+https://github.com/ethereum/c-kzg-4844#f5f6f863d475847876a2bd5ee252058d37c3a15d" +dependencies = [ + "bindgen", + "blst", + "cc", + "glob", + "hex", + "libc", +] + [[package]] name = "cast" version = "0.3.0" @@ -420,6 +468,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -463,6 +520,17 @@ dependencies = [ "half", ] +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "2.34.0" @@ -895,9 +963,9 @@ dependencies = [ [[package]] name = "ethers-contract" -version = "2.0.9" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bb80fd2c22631a5eb8a02cbf373cc5fd86937fc966bb670b9a884580c8e71c" +checksum = "d79269278125006bb0552349c03593ffa9702112ca88bc7046cc669f148fb47c" dependencies = [ "const-hex", "ethers-core", @@ -911,9 +979,9 @@ dependencies = [ [[package]] name = "ethers-core" -version = "2.0.9" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c29523f73c12753165781c6e5dc11c84d3e44c080a15f7c6cfbd70b514cb6f1" +checksum = "c0a17f0708692024db9956b31d7a20163607d2745953f5ae8125ab368ba280ad" dependencies = [ "arrayvec", "bytes", @@ -938,9 +1006,9 @@ dependencies = [ [[package]] name = "ethers-providers" -version = "2.0.9" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c84664b294e47fc2860d6db0db0246f79c4c724e552549631bb9505b834bee" +checksum = "6838fa110e57d572336178b7c79e94ff88ef976306852d8cb87d9e5b1fc7c0b5" dependencies = [ "async-trait", "auto_impl", @@ -1170,6 +1238,12 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -1553,12 +1627,28 @@ dependencies = [ "spin", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libm" version = "0.2.7" @@ -1604,6 +1694,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1630,6 +1726,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num" version = "0.4.1" @@ -1822,6 +1928,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem" version = "1.1.1" @@ -1948,6 +2060,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +dependencies = [ + "proc-macro2", + "syn 2.0.28", +] + [[package]] name = "primitive-types" version = "0.12.1" @@ -2215,7 +2337,6 @@ dependencies = [ "futures", "hex", "hex-literal", - "rayon", "revm-interpreter", "revm-precompile", "serde", @@ -2241,6 +2362,7 @@ dependencies = [ name = "revm-precompile" version = "2.0.3" dependencies = [ + "c-kzg", "hex", "k256", "num", @@ -2262,12 +2384,14 @@ dependencies = [ "bitflags 2.4.0", "bitvec", "bytes", + "c-kzg", "derive_more", "enumn", "fixed-hash", "hashbrown 0.14.0", "hex", "hex-literal", + "once_cell", "primitive-types", "proptest", "proptest-derive", @@ -2393,6 +2517,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -2645,9 +2775,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" dependencies = [ "indexmap 2.0.0", "itoa", @@ -2699,6 +2829,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "signature" version = "2.1.0" @@ -2931,6 +3067,15 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.28" @@ -3396,6 +3541,17 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 3a418746f3..f76b7605fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,3 @@ - [workspace] resolver = "2" members = ["bins/*", "crates/*"] diff --git a/README.md b/README.md index f944860d4a..e5ef67299f 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,16 @@ Here is a list of things that I would like to use as guide in this project: # Project -structure: +Structure: * crates * revm -> main EVM library. * revm-primitives -> Primitive data types. * revm-interpreter -> Execution loop with instructions * revm-precompile -> EVM precompiles * bins: - * revme: cli binary, used for running state test json - * revm-test: test binaries with contracts, used mostly to check performance + * revme: cli binary, used for running state test jsons -Last checked revm requires rust v1.65 or higher for `core::error::Error` +This project tends to use the newest rust version, so if you're encountering a build error try running `rustup update` first. There were some big efforts on optimization of revm: * Optimizing interpreter loop: https://github.com/bluealloy/revm/issues/7 @@ -40,6 +39,8 @@ run tests with command: `cargo run --release -- statetest tests/GeneralStateTest ## Running benchmarks +TODO needs to be updated. Benches can now be found inside `crates/revm/benches` + ```shell cargo run --package revm-test --release --bin snailtracer ``` @@ -56,18 +57,23 @@ cargo run -p revm --features ethersdb --example fork_ref_transact # Used by: -* Foundry: https://github.com/foundry-rs/foundry -* Helios: https://github.com/a16z/helios -* Hardhat (transitioning to it): https://github.com/NomicFoundation/hardhat/tree/rethnet/main -* Reth: https://github.com/paradigmxyz/reth -* Arbiter: https://github.com/primitivefinance/arbiter +* [Foundry](https://github.com/foundry-rs/foundry) is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. +* [Helios](https://github.com/a16z/helios) is a fully trustless, efficient, and portable Ethereum light client written in Rust. +* [Reth](https://github.com/paradigmxyz/reth) Modular, contributor-friendly and blazing-fast implementation of the Ethereum protocol +* [Arbiter](https://github.com/primitivefinance/arbiter) is a framework for stateful Ethereum smart-contract simulation +* [Zeth](https://github.com/risc0/zeth) is an open-source ZK block prover for Ethereum built on the RISC Zero zkVM. +* ... -(If you want to add your project to the list, ping me or open the PR) +(If you want to add project to the list, ping me or open the PR) # Documentation -To serve the mdbook documentation, ensure you have mdbook installed (if not install it with cargo) and then run: +The book can be found at github page here: https://bluealloy.github.io/revm/ + +The documentation (alas needs some love) can be found here: https://bluealloy.github.io/revm/docs/ + +To serve the mdbook documentation in a local environment, ensure you have mdbook installed (if not install it with cargo) and then run: ```shell mdbook serve documentation diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index c777890d39..30ac210af5 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -10,7 +10,7 @@ version = "0.2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bytes = "1.4" +bytes = "1.5" hash-db = "0.15" hashbrown = "0.14" hex = "0.4" diff --git a/bins/revme/src/cmd.rs b/bins/revme/src/cmd.rs index 8c833c78cc..d9220f0b31 100644 --- a/bins/revme/src/cmd.rs +++ b/bins/revme/src/cmd.rs @@ -1,4 +1,4 @@ -use crate::{runner, statetest}; +use crate::statetest; use structopt::{clap::AppSettings, StructOpt}; #[derive(StructOpt, Debug)] @@ -6,24 +6,18 @@ use structopt::{clap::AppSettings, StructOpt}; #[allow(clippy::large_enum_variant)] pub enum MainCmd { Statetest(statetest::Cmd), - Run(runner::Cmd), } -use thiserror::Error as ThisError; - -#[derive(Debug, ThisError)] +#[derive(Debug, thiserror::Error)] pub enum Error { - #[error("Statetest: {0}")] - Statetest(statetest::Error), - #[error("Generic system error")] - SystemError, + #[error(transparent)] + Statetest(#[from] statetest::Error), } impl MainCmd { pub fn run(&self) -> Result<(), Error> { match self { - Self::Statetest(cmd) => cmd.run().map_err(Error::Statetest), - _ => Ok(()), + Self::Statetest(cmd) => cmd.run().map_err(Into::into), } } } diff --git a/bins/revme/src/exec.rs b/bins/revme/src/exec.rs deleted file mode 100644 index 4bde5497b5..0000000000 --- a/bins/revme/src/exec.rs +++ /dev/null @@ -1 +0,0 @@ -//pub struct Runner {} diff --git a/bins/revme/src/main.rs b/bins/revme/src/main.rs index 70a2999c67..d7ab296ce3 100644 --- a/bins/revme/src/main.rs +++ b/bins/revme/src/main.rs @@ -1,10 +1,9 @@ -mod cmd; -mod exec; -mod runner; -mod statetest; use cmd::Error; use structopt::StructOpt; + mod cli_env; +mod cmd; +mod statetest; pub fn main() -> Result<(), Error> { let cmd = cmd::MainCmd::from_args(); diff --git a/bins/revme/src/parser.rs b/bins/revme/src/parser.rs deleted file mode 100644 index 3f2ff2d6cc..0000000000 --- a/bins/revme/src/parser.rs +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/bins/revme/src/runner/mod.rs b/bins/revme/src/runner/mod.rs deleted file mode 100644 index f90bd477b7..0000000000 --- a/bins/revme/src/runner/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -use structopt::StructOpt; - -#[derive(StructOpt, Debug)] -pub struct Cmd {} diff --git a/bins/revme/src/state.rs b/bins/revme/src/state.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/bins/revme/src/statetest/cmd.rs b/bins/revme/src/statetest/cmd.rs index f66aa6d706..d277e6de47 100644 --- a/bins/revme/src/statetest/cmd.rs +++ b/bins/revme/src/statetest/cmd.rs @@ -16,7 +16,7 @@ pub struct Cmd { impl Cmd { pub fn run(&self) -> Result<(), TestError> { for path in &self.path { - println!("Start running tests on: {path:?}"); + println!("\nRunning tests in {}...", path.display()); let test_files = find_all_json_tests(path); run(test_files, self.single_thread, self.json)? } diff --git a/bins/revme/src/statetest/main.rs b/bins/revme/src/statetest/main.rs deleted file mode 100644 index ce6699c11e..0000000000 --- a/bins/revme/src/statetest/main.rs +++ /dev/null @@ -1,26 +0,0 @@ -mod merkle_trie; -mod models; -mod runner; -mod trace; - -use std::{env, path::PathBuf}; - -pub fn main() { - let args: Vec = env::args().collect(); - println!("args:{:?}", args); - let folder_path = if args.len() == 1 { - //tests/GeneralStateTests/ - //temp_folder" - "./bins/revm-ethereum-tests/temp_folder" - } else { - let second = &args[1]; - if second == "eth" { - "./bins/revm-ethereum-tests/tests/GeneralStateTests" - } else { - second - } - }; - let test_files = runner::find_all_json_tests(PathBuf::from(folder_path)); - println!("Start running tests on: {:?}", folder_path); - runner::run(test_files); -} diff --git a/bins/revme/src/statetest/models/mod.rs b/bins/revme/src/statetest/models/mod.rs index 9b94cef315..2f63099e95 100644 --- a/bins/revme/src/statetest/models/mod.rs +++ b/bins/revme/src/statetest/models/mod.rs @@ -1,20 +1,23 @@ use bytes::Bytes; use revm::primitives::{HashMap, B160, B256, U256}; +use serde::Deserialize; use std::collections::BTreeMap; -mod deserializer; -mod spec; +mod deserializer; use deserializer::*; -use serde::Deserialize; - +mod spec; pub use self::spec::SpecName; #[derive(Debug, PartialEq, Eq, Deserialize)] -pub struct TestSuit(pub BTreeMap); +pub struct TestSuite(pub BTreeMap); #[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(deny_unknown_fields)] pub struct TestUnit { + #[serde(rename = "_info")] + pub info: serde_json::Value, + pub env: Env, pub pre: HashMap, pub post: BTreeMap>, @@ -23,19 +26,29 @@ pub struct TestUnit { /// State test indexed state result deserialization. #[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Test { - /// Post state hash - pub hash: B256, + pub expect_exception: Option, + /// Indexes pub indexes: TxPartIndices, - // logs - pub logs: B256, + + /// Post state hash + pub hash: B256, + /// Post state #[serde(default)] - #[serde(deserialize_with = "deserialize_opt_str_as_bytes")] + pub post_state: HashMap, + + /// Logs root + pub logs: B256, + + /// Tx bytes + #[serde(default, deserialize_with = "deserialize_opt_str_as_bytes")] pub txbytes: Option, } #[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct TxPartIndices { pub data: usize, pub gas: usize, @@ -43,8 +56,7 @@ pub struct TxPartIndices { } #[derive(Clone, Debug, PartialEq, Eq, Deserialize)] -#[serde(deny_unknown_fields)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct AccountInfo { pub balance: U256, #[serde(deserialize_with = "deserialize_str_as_bytes")] @@ -55,7 +67,7 @@ pub struct AccountInfo { } #[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Env { pub current_coinbase: B160, #[serde(default, deserialize_with = "deserialize_str_as_u256")] @@ -68,27 +80,41 @@ pub struct Env { pub current_timestamp: U256, pub current_base_fee: Option, pub previous_hash: B256, + + pub current_random: Option, + pub current_beacon_root: Option, + pub current_withdrawals_root: Option, + + pub parent_blob_gas_used: Option, + pub parent_excess_blob_gas: Option, } #[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct TransactionParts { #[serde(deserialize_with = "deserialize_vec_as_vec_bytes")] pub data: Vec, - pub access_lists: Option>>, pub gas_limit: Vec, pub gas_price: Option, pub nonce: U256, - pub secret_key: Option, + pub secret_key: B256, + pub sender: B160, #[serde(deserialize_with = "deserialize_maybe_empty")] pub to: Option, pub value: Vec, pub max_fee_per_gas: Option, pub max_priority_fee_per_gas: Option, + + #[serde(default)] + pub access_lists: Vec>, + + #[serde(default)] + pub blob_versioned_hashes: Vec, + pub max_fee_per_blob_gas: Option, } #[derive(Debug, PartialEq, Eq, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct AccessListItem { pub address: B160, pub storage_keys: Vec, diff --git a/bins/revme/src/statetest/runner.rs b/bins/revme/src/statetest/runner.rs index bee54a837c..e8cccdc4c6 100644 --- a/bins/revme/src/statetest/runner.rs +++ b/bins/revme/src/statetest/runner.rs @@ -1,6 +1,6 @@ use super::{ merkle_trie::{log_rlp_hash, state_merkle_trie_root}, - models::{SpecName, TestSuit}, + models::{SpecName, TestSuite}, }; use hex_literal::hex; use indicatif::ProgressBar; @@ -8,11 +8,11 @@ use revm::{ inspectors::TracerEip3155, interpreter::CreateScheme, primitives::{ - keccak256, Bytecode, Env, ExecutionResult, HashMap, SpecId, TransactTo, B160, B256, U256, + calc_excess_blob_gas, keccak256, Bytecode, Env, ExecutionResult, HashMap, SpecId, + TransactTo, B160, B256, U256, }, }; use std::{ - ffi::OsStr, io::stdout, path::{Path, PathBuf}, sync::atomic::Ordering, @@ -23,20 +23,22 @@ use thiserror::Error; use walkdir::{DirEntry, WalkDir}; #[derive(Debug, Error)] -pub enum TestError { - #[error("Test: {id} ({spec_id:?}), root mismatched, expected: {expect:?} got: {got:?}")] - RootMismatch { - spec_id: SpecId, - id: usize, - got: B256, - expect: B256, - }, - #[error("Serde json error")] +#[error("Test {name} failed: {kind}")] +pub struct TestError { + pub name: String, + pub kind: TestErrorKind, +} + +#[derive(Debug, Error)] +pub enum TestErrorKind { + #[error("logs root mismatch: expected {expected:?}, got {got:?}")] + LogsRootMismatch { got: B256, expected: B256 }, + #[error("state root mismatch: expected {expected:?}, got {got:?}")] + StateRootMismatch { got: B256, expected: B256 }, + #[error("Unknown private key: {0:?}")] + UnknownPrivateKey(B256), + #[error(transparent)] SerdeDeserialize(#[from] serde_json::Error), - #[error("Internal system error")] - SystemError, - #[error("Unknown private key: {private_key:?}")] - UnknownPrivateKey { private_key: B256 }, } pub fn find_all_json_tests(path: &Path) -> Vec { @@ -48,75 +50,74 @@ pub fn find_all_json_tests(path: &Path) -> Vec { .collect::>() } -pub fn execute_test_suit( +fn skip_test(path: &Path) -> bool { + let path_str = path.to_str().expect("Path is not valid UTF-8"); + let name = path.file_name().unwrap().to_str().unwrap(); + + matches!( + name, + // funky test with `bigint 0x00` value in json :) not possible to happen on mainnet and require + // custom json parser. https://github.com/ethereum/tests/issues/971 + | "ValueOverflow.json" + + // precompiles having storage is not possible + | "RevertPrecompiledTouch_storage.json" + | "RevertPrecompiledTouch.json" + + // txbyte is of type 02 and we dont parse tx bytes for this test to fail. + | "typeTwoBerlin.json" + + // Test checks if nonce overflows. We are handling this correctly but we are not parsing + // exception in testsuite There are more nonce overflow tests that are in internal + // call/create, and those tests are passing and are enabled. + | "CreateTransactionHighNonce.json" + + // Need to handle Test errors + | "transactionIntinsicBug.json" + + // Test check if gas price overflows, we handle this correctly but does not match tests specific exception. + | "HighGasPrice.json" + | "CREATE_HighNonce.json" + | "CREATE_HighNonceMinus1.json" + + // Skip test where basefee/accesslist/difficulty is present but it shouldn't be supported in + // London/Berlin/TheMerge. https://github.com/ethereum/tests/blob/5b7e1ab3ffaf026d99d20b17bb30f533a2c80c8b/GeneralStateTests/stExample/eip1559.json#L130 + // It is expected to not execute these tests. + | "accessListExample.json" + | "basefeeExample.json" + | "eip1559.json" + | "mergeTest.json" + + // These tests are passing, but they take a lot of time to execute so we are going to skip them. + | "loopExp.json" + | "Call50000_sha256.json" + | "static_Call50000_sha256.json" + | "loopMul.json" + | "CALLBlake2f_MaxRounds.json" + | "shiftCombinations.json" + + // TODO: These EIP-4844 all have exception specified. + | "emptyBlobhashList.json" // '>=Cancun': TR_EMPTYBLOB + | "wrongBlobhashVersion.json" // '>=Cancun': TR_BLOBVERSION_INVALID + | "createBlobhashTx.json" // '>=Cancun': TR_BLOBCREATE + | "blobhashListBounds7.json" // ">=Cancun": "TR_BLOBLIST_OVERSIZE" + ) || path_str.contains("stEOF") +} + +pub fn execute_test_suite( path: &Path, elapsed: &Arc>, trace: bool, ) -> Result<(), TestError> { - // funky test with `bigint 0x00` value in json :) not possible to happen on mainnet and require custom json parser. - // https://github.com/ethereum/tests/issues/971 - if path.file_name() == Some(OsStr::new("ValueOverflow.json")) { - return Ok(()); - } - - // precompiles having storage is not possible - if path.file_name() == Some(OsStr::new("RevertPrecompiledTouch_storage.json")) - || path.file_name() == Some(OsStr::new("RevertPrecompiledTouch.json")) - { - return Ok(()); - } - - // txbyte is of type 02 and we dont parse tx bytes for this test to fail. - if path.file_name() == Some(OsStr::new("typeTwoBerlin.json")) { - return Ok(()); - } - - // Test checks if nonce overflows. We are handling this correctly but we are not parsing exception in test suite - // There are more nonce overflow tests that are in internal call/create, and those tests are passing and are enabled. - if path.file_name() == Some(OsStr::new("CreateTransactionHighNonce.json")) { - return Ok(()); - } - - // Need to handle Test errors - if path.file_name() == Some(OsStr::new("transactionIntinsicBug.json")) { - return Ok(()); - } - - // Test check if gas price overflows, we handle this correctly but does not match tests specific exception. - if path.file_name() == Some(OsStr::new("HighGasPrice.json")) - || path.file_name() == Some(OsStr::new("CREATE_HighNonce.json")) - || path.file_name() == Some(OsStr::new("CREATE_HighNonceMinus1.json")) - { - return Ok(()); - } - - // Skip test where basefee/accesslist/difficulty is present but it shouldn't be supported in London/Berlin/TheMerge. - // https://github.com/ethereum/tests/blob/5b7e1ab3ffaf026d99d20b17bb30f533a2c80c8b/GeneralStateTests/stExample/eip1559.json#L130 - // It is expected to not execute these tests. - if path.file_name() == Some(OsStr::new("accessListExample.json")) - || path.file_name() == Some(OsStr::new("basefeeExample.json")) - || path.file_name() == Some(OsStr::new("eip1559.json")) - || path.file_name() == Some(OsStr::new("mergeTest.json")) - { + if skip_test(path) { return Ok(()); } - // These tests are passing, but they take a lot of time to execute so we are going to skip them. - if path.file_name() == Some(OsStr::new("loopExp.json")) - || path.file_name() == Some(OsStr::new("Call50000_sha256.json")) - || path.file_name() == Some(OsStr::new("static_Call50000_sha256.json")) - || path.file_name() == Some(OsStr::new("loopMul.json")) - || path.file_name() == Some(OsStr::new("CALLBlake2f_MaxRounds.json")) - { - return Ok(()); - } - - if path.to_str().unwrap().contains("stEOF") { - return Ok(()); - } - - let json_reader = std::fs::read(path).unwrap(); - let suit: TestSuit = serde_json::from_reader(&*json_reader)?; + let s = std::fs::read_to_string(path).unwrap(); + let suite: TestSuite = serde_json::from_str(&s).map_err(|e| TestError { + name: path.to_string_lossy().into_owned(), + kind: e.into(), + })?; let map_caller_keys: HashMap<_, _> = [ ( @@ -158,21 +159,23 @@ pub fn execute_test_suit( ] .into(); - for (name, unit) in suit.0.into_iter() { + for (name, unit) in suite.0 { // Create database and insert cache let mut cache_state = revm::CacheState::new(false); - for (address, info) in unit.pre.into_iter() { + for (address, info) in unit.pre { let acc_info = revm::primitives::AccountInfo { balance: info.balance, - code_hash: keccak256(&info.code), // try with dummy hash. - code: Some(Bytecode::new_raw(info.code.clone())), + code_hash: keccak256(&info.code), + code: Some(Bytecode::new_raw(info.code)), nonce: info.nonce, }; - cache_state.insert_account_with_storage(address, acc_info, info.storage.clone()); + cache_state.insert_account_with_storage(address, acc_info, info.storage); } + let mut env = Env::default(); - // cfg env. SpecId is set down the road - env.cfg.chain_id = 1; // for mainnet + // for mainnet + env.cfg.chain_id = 1; + // env.cfg.spec_id is set down the road // block env env.block.number = unit.env.current_number; @@ -183,20 +186,32 @@ pub fn execute_test_suit( env.block.difficulty = unit.env.current_difficulty; // after the Merge prevrandao replaces mix_hash field in block and replaced difficulty opcode in EVM. env.block.prevrandao = Some(unit.env.current_difficulty.to_be_bytes().into()); + // EIP-4844 + if let (Some(parent_blob_gas_used), Some(parent_excess_blob_gas)) = ( + unit.env.parent_blob_gas_used, + unit.env.parent_excess_blob_gas, + ) { + env.block.excess_blob_gas = Some(calc_excess_blob_gas( + parent_blob_gas_used.to(), + parent_excess_blob_gas.to(), + )); + } - //tx env - env.tx.caller = - if let Some(caller) = map_caller_keys.get(&unit.transaction.secret_key.unwrap()) { - *caller - } else { - let private_key = unit.transaction.secret_key.unwrap(); - return Err(TestError::UnknownPrivateKey { private_key }); - }; + // tx env + let pk = unit.transaction.secret_key; + env.tx.caller = map_caller_keys.get(&pk).copied().ok_or_else(|| TestError { + name: name.clone(), + kind: TestErrorKind::UnknownPrivateKey(pk), + })?; env.tx.gas_price = unit .transaction .gas_price - .unwrap_or_else(|| unit.transaction.max_fee_per_gas.unwrap_or_default()); + .or(unit.transaction.max_fee_per_gas) + .unwrap_or_default(); env.tx.gas_priority_fee = unit.transaction.max_priority_fee_per_gas; + // EIP-4844 + env.tx.blob_hashes = unit.transaction.blob_versioned_hashes; + env.tx.max_fee_per_blob_gas = unit.transaction.max_fee_per_blob_gas; // post and execution for (spec_name, tests) in unit.post { @@ -223,26 +238,23 @@ pub fn execute_test_suit( .clone(); env.tx.value = *unit.transaction.value.get(test.indexes.value).unwrap(); - let access_list = match unit.transaction.access_lists { - Some(ref access_list) => access_list - .get(test.indexes.data) - .cloned() - .flatten() - .unwrap_or_default() - .into_iter() - .map(|item| { - ( - item.address, - item.storage_keys - .into_iter() - .map(|key| U256::from_be_bytes(key.0)) - .collect::>(), - ) - }) - .collect(), - None => Vec::new(), - }; - env.tx.access_list = access_list; + env.tx.access_list = unit + .transaction + .access_lists + .get(test.indexes.data) + .and_then(Option::as_deref) + .unwrap_or_default() + .iter() + .map(|item| { + ( + item.address, + item.storage_keys + .iter() + .map(|key| U256::from_be_bytes(key.0)) + .collect::>(), + ) + }) + .collect(); let to = match unit.transaction.to { Some(add) => TransactTo::Call(add), @@ -262,82 +274,83 @@ pub fn execute_test_suit( let mut evm = revm::new(); evm.database(&mut state); evm.env = env.clone(); - // do the deed + // do the deed let timer = Instant::now(); - let exec_result = if trace { evm.inspect_commit(TracerEip3155::new(Box::new(stdout()), false, false)) } else { evm.transact_commit() }; - let timer = timer.elapsed(); + *elapsed.lock().unwrap() += timer.elapsed(); + + // validate results + // this is in a closure so we can have a common printing routine for errors + let check = || { + let logs = match &exec_result { + Ok(ExecutionResult::Success { logs, .. }) => logs.clone(), + _ => Vec::new(), + }; + let logs_root = log_rlp_hash(logs); + + if logs_root != test.logs { + return Err(TestError { + name: name.clone(), + kind: TestErrorKind::LogsRootMismatch { + got: logs_root, + expected: test.logs, + }, + }); + } - *elapsed.lock().unwrap() += timer; + let db = evm.db.as_ref().unwrap(); + let state_root = state_merkle_trie_root(db.cache.trie_account()); + + if state_root != test.hash { + return Err(TestError { + name: name.clone(), + kind: TestErrorKind::StateRootMismatch { + got: state_root, + expected: test.hash, + }, + }); + } - let db = evm.db().unwrap(); - let state_root = state_merkle_trie_root(db.cache.trie_account()); - let logs = match &exec_result { - Ok(ExecutionResult::Success { logs, .. }) => logs.clone(), - _ => Vec::new(), + Ok(()) }; - let logs_root = log_rlp_hash(logs); - if test.hash != state_root || test.logs != logs_root { - println!( - "Roots did not match:\nState root: wanted {:?}, got {state_root:?}\nLogs root: wanted {:?}, got {logs_root:?}", - test.hash, test.logs - ); - - let mut cache = cache_state.clone(); - cache.set_state_clear_flag(SpecId::enabled( - env.cfg.spec_id, - revm::primitives::SpecId::SPURIOUS_DRAGON, - )); - let mut state = revm::db::StateBuilder::default() - .with_cached_prestate(cache) - .with_bundle_update() - .build(); - evm.database(&mut state); - let _ = - evm.inspect_commit(TracerEip3155::new(Box::new(stdout()), false, false)); - let db = evm.db().unwrap(); - println!("{path:?} UNIT_TEST:{name}\n"); - match &exec_result { - Ok(ExecutionResult::Success { - reason, - gas_used, - gas_refunded, - .. - }) => { - println!("Failed reason: {reason:?} {path:?} UNIT_TEST:{name}\n gas:{gas_used:?} ({gas_refunded:?} refunded)"); - } - Ok(ExecutionResult::Revert { gas_used, output }) => { - println!( - "Reverted: {output:?} {path:?} UNIT_TEST:{name}\n gas:{gas_used:?}" - ); - } - Ok(ExecutionResult::Halt { reason, gas_used }) => { - println!( - "Halted: {reason:?} {path:?} UNIT_TEST:{name}\n gas:{gas_used:?}" - ); - } - Err(out) => { - println!("Output: {out:?} {path:?} UNIT_TEST:{name}\n"); - } - } - println!(" TEST NAME: {:?}", name); - println!("\nApplied state:\n{:#?}\n", db.cache); - println!("\nState root: {state_root:?}\n"); - println!("env.tx: {:?}\n", env.tx); - println!("env.block: {:?}\n", env.block); - println!("env.cfg: {:?}\n", env.cfg); - return Err(TestError::RootMismatch { - spec_id: env.cfg.spec_id, - id, - got: state_root, - expect: test.hash, - }); + + // dump state and traces if test failed + let Err(e) = check() else { continue }; + + // print only once + static FAILED: AtomicBool = AtomicBool::new(false); + if FAILED.swap(true, Ordering::SeqCst) { + return Err(e); } + + // re build to run with tracing + let mut cache = cache_state.clone(); + cache.set_state_clear_flag(SpecId::enabled( + env.cfg.spec_id, + revm::primitives::SpecId::SPURIOUS_DRAGON, + )); + let mut state = revm::db::StateBuilder::default() + .with_cached_prestate(cache) + .build(); + evm.database(&mut state); + + let path = path.display(); + println!("Test {name:?} (id: {id}, path: {path}) failed:\n{e}"); + + println!("\nTraces:"); + let _ = evm.inspect_commit(TracerEip3155::new(Box::new(stdout()), false, false)); + + println!("\nExecution result: {exec_result:#?}"); + println!("\nExpected exception: {:?}", test.expect_exception); + println!("\nState before: {cache_state:#?}"); + println!("\nState after: {:#?}", evm.db().unwrap().cache); + println!("\nEnvironment: {env:#?}"); + return Err(e); } } } @@ -352,58 +365,77 @@ pub fn run( if trace { single_thread = true; } + let n_files = test_files.len(); let endjob = Arc::new(AtomicBool::new(false)); - let console_bar = Arc::new(ProgressBar::new(test_files.len() as u64)); - let mut joins: Vec>> = Vec::new(); - let queue = Arc::new(Mutex::new((0, test_files))); + let console_bar = Arc::new(ProgressBar::new(n_files as u64)); + let queue = Arc::new(Mutex::new((0usize, test_files))); let elapsed = Arc::new(Mutex::new(std::time::Duration::ZERO)); - let num_threads = if single_thread { 1 } else { 10 }; - for _ in 0..num_threads { + + let num_threads = match (single_thread, std::thread::available_parallelism()) { + (true, _) | (false, Err(_)) => 1, + (false, Ok(n)) => n.get(), + }; + let num_threads = num_threads.min(n_files); + let mut handles = Vec::with_capacity(num_threads); + for i in 0..num_threads { let queue = queue.clone(); let endjob = endjob.clone(); let console_bar = console_bar.clone(); let elapsed = elapsed.clone(); - let mut thread = std::thread::Builder::new(); - - // Allow bigger stack in debug mode to prevent stack overflow errors - //if cfg!(debug_assertions) { - thread = thread.stack_size(4 * 1024 * 1024); - //} - - joins.push( - thread - .spawn(move || loop { - let (index, test_path) = { - let mut queue = queue.lock().unwrap(); - if queue.1.len() <= queue.0 { - return Ok(()); - } - let test_path = queue.1[queue.0].clone(); - queue.0 += 1; - (queue.0 - 1, test_path) - }; - if endjob.load(Ordering::SeqCst) { - return Ok(()); - } - //println!("Test:{:?}\n",test_path); - if let Err(err) = execute_test_suit(&test_path, &elapsed, trace) { - endjob.store(true, Ordering::SeqCst); - println!("Test[{index}] named:\n{test_path:?} failed: {err}\n"); - return Err(err); - } + let thread = std::thread::Builder::new().name(format!("runner-{i}")); + + let f = move || loop { + if endjob.load(Ordering::SeqCst) { + return Ok(()); + } - //println!("TestDone:{:?}\n",test_path); - console_bar.inc(1); - }) - .unwrap(), - ); + let (_index, test_path) = { + let (current_idx, queue) = &mut *queue.lock().unwrap(); + let prev_idx = *current_idx; + let Some(test_path) = queue.get(prev_idx).cloned() else { + return Ok(()); + }; + *current_idx = prev_idx + 1; + (prev_idx, test_path) + }; + + if let Err(err) = execute_test_suite(&test_path, &elapsed, trace) { + endjob.store(true, Ordering::SeqCst); + return Err(err); + } + + console_bar.inc(1); + }; + handles.push(thread.spawn(f).unwrap()); } - for handler in joins { - handler.join().map_err(|_| TestError::SystemError)??; + + // join all threads before returning an error + let mut errors = Vec::new(); + for handle in handles { + if let Err(e) = handle.join().unwrap() { + errors.push(e); + } } + console_bar.finish(); - println!("Finished execution. Time:{:?}", elapsed.lock().unwrap()); - Ok(()) + + println!( + "Finished execution. Total CPU time: {:.6}s", + elapsed.lock().unwrap().as_secs_f64() + ); + if errors.is_empty() { + println!("All tests passed!"); + Ok(()) + } else { + let n = errors.len(); + if n > 1 { + println!("{n} threads returned an error, out of {num_threads} total:"); + for error in &errors { + println!("{error}"); + } + } + Err(errors.swap_remove(0)) + } } diff --git a/book.toml b/book.toml index 835363e927..ffe9273021 100644 --- a/book.toml +++ b/book.toml @@ -5,7 +5,6 @@ multilingual = false src = "documentation/src" title = "Rust EVM" - [output.linkcheck] optional = true -follow-web-links = true \ No newline at end of file +follow-web-links = true diff --git a/crates/interpreter/src/instructions.rs b/crates/interpreter/src/instructions.rs index 7eee8cf455..b58d51db0a 100644 --- a/crates/interpreter/src/instructions.rs +++ b/crates/interpreter/src/instructions.rs @@ -60,6 +60,7 @@ pub fn eval(opcode: u8, interp: &mut Interpreter, host: &mut H opcode::ADDRESS => system::address(interp, host), opcode::BALANCE => host::balance::(interp, host), opcode::SELFBALANCE => host::selfbalance::(interp, host), + opcode::BLOBHASH => host_env::blob_hash::(interp, host), opcode::CODESIZE => system::codesize(interp, host), opcode::CODECOPY => system::codecopy(interp, host), opcode::CALLDATALOAD => system::calldataload(interp, host), diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index 95d549d633..5fbfa20253 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -239,6 +239,7 @@ pub fn selfdestruct(interpreter: &mut Interpreter, host: &mut dyn Ho interpreter.instruction_result = InstructionResult::SelfDestruct; } +#[inline(never)] pub fn prepare_create_inputs( interpreter: &mut Interpreter, host: &mut dyn Host, @@ -368,6 +369,7 @@ pub fn static_call(interpreter: &mut Interpreter, host: &mut dyn Hos call_inner::(interpreter, CallScheme::StaticCall, host); } +#[inline(never)] fn prepare_call_inputs( interpreter: &mut Interpreter, scheme: CallScheme, diff --git a/crates/interpreter/src/instructions/host_env.rs b/crates/interpreter/src/instructions/host_env.rs index f666a59e83..7f64970509 100644 --- a/crates/interpreter/src/instructions/host_env.rs +++ b/crates/interpreter/src/instructions/host_env.rs @@ -1,7 +1,8 @@ -use revm_primitives::U256; - use crate::{ - gas, interpreter::Interpreter, primitives::Spec, primitives::SpecId::*, Host, InstructionResult, + gas, + interpreter::Interpreter, + primitives::{Spec, SpecId::*, U256}, + Host, InstructionResult, }; pub fn chainid(interpreter: &mut Interpreter, host: &mut dyn Host) { @@ -56,3 +57,15 @@ pub fn origin(interpreter: &mut Interpreter, host: &mut dyn Host) { gas!(interpreter, gas::BASE); push_b256!(interpreter, host.env().tx.caller.into()); } + +// EIP-4844: Shard Blob Transactions +pub fn blob_hash(interpreter: &mut Interpreter, host: &mut dyn Host) { + check!(interpreter, SPEC::enabled(CANCUN)); + gas!(interpreter, gas::VERYLOW); + pop_top!(interpreter, index); + let i = as_usize_saturated!(index); + *index = match host.env().tx.blob_hashes.get(i) { + Some(hash) => U256::from_be_bytes(hash.0), + None => U256::ZERO, + }; +} diff --git a/crates/interpreter/src/instructions/opcode.rs b/crates/interpreter/src/instructions/opcode.rs index ab042cbd4e..f7ceced8f5 100644 --- a/crates/interpreter/src/instructions/opcode.rs +++ b/crates/interpreter/src/instructions/opcode.rs @@ -140,6 +140,7 @@ pub const NUMBER: u8 = 0x43; pub const DIFFICULTY: u8 = 0x44; pub const GASLIMIT: u8 = 0x45; pub const SELFBALANCE: u8 = 0x47; +pub const BLOBHASH: u8 = 0x49; pub const SLOAD: u8 = 0x54; pub const SSTORE: u8 = 0x55; pub const GAS: u8 = 0x5a; @@ -262,7 +263,7 @@ pub const OPCODE_JUMPMAP: [Option<&'static str>; 256] = [ /* 0x46 */ Some("CHAINID"), /* 0x47 */ Some("SELFBALANCE"), /* 0x48 */ Some("BASEFEE"), - /* 0x49 */ None, + /* 0x49 */ Some("BLOBHASH"), /* 0x4a */ None, /* 0x4b */ None, /* 0x4c */ None, @@ -642,7 +643,12 @@ macro_rules! gas_opcodee { } else { 0 }), - /* 0x49 */ OpInfo::none(), + /* 0x49 BLOBHASH */ + OpInfo::gas(if SpecId::enabled($spec_id, SpecId::CANCUN) { + gas::VERYLOW + } else { + 0 + }), /* 0x4a */ OpInfo::none(), /* 0x4b */ OpInfo::none(), /* 0x4c */ OpInfo::none(), diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 09090dbcc7..c5eddc1f41 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -8,6 +8,9 @@ name = "revm-precompile" repository = "https://github.com/bluealloy/revm" version = "2.0.3" +# Don't need to run build script outside of this repo +exclude = ["build.rs", "src/blob/kzg_settings/*.txt"] + [dependencies] revm-primitives = { path = "../primitives", version = "1.1.2", default-features = false } bn = { package = "substrate-bn", version = "0.6", default-features = false } @@ -21,12 +24,19 @@ secp256k1 = { version = "0.27.0", default-features = false, features = [ ], optional = true } sha2 = { version = "0.10.5", default-features = false } sha3 = { version = "0.10.7", default-features = false } +c-kzg = { git = "https://github.com/ethereum/c-kzg-4844", default-features = false, optional = true } [dev-dependencies] hex = "0.4" +[build-dependencies] +hex = "0.4" + [features] -default = ["secp256k1"] +default = ["secp256k1", "std"] +# Used to disable kzg lib as i couldn't make it compile for wasm target +# at least not on mac. +std = ["dep:c-kzg"] # secp256k1 is used as faster alternative to k256 lib. And in most cases should be default. # Only problem that it has, it fails to build for wasm target on windows and mac as it is c lib. # If you dont require wasm on win/mac, i would recommend its usage. diff --git a/crates/precompile/src/kzg_point_evaluation.rs b/crates/precompile/src/kzg_point_evaluation.rs new file mode 100644 index 0000000000..ec85ac3d94 --- /dev/null +++ b/crates/precompile/src/kzg_point_evaluation.rs @@ -0,0 +1,118 @@ +use crate::{Error, Precompile, PrecompileAddress, PrecompileResult, B160}; +use c_kzg::{Bytes32, Bytes48, KzgProof, KzgSettings}; +use revm_primitives::{hex_literal::hex, Env}; +use sha2::{Digest, Sha256}; + +pub const POINT_EVALUATION: PrecompileAddress = PrecompileAddress(ADDRESS, Precompile::Env(run)); + +const ADDRESS: B160 = crate::u64_to_b160(0x0A); +const GAS_COST: u64 = 50_000; +const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; + +/// `U256(FIELD_ELEMENTS_PER_BLOB).to_be_bytes() ++ BLS_MODULUS.to_bytes32()` +const RETURN_VALUE: &[u8; 64] = &hex!( + "0000000000000000000000000000000000000000000000000000000000001000" + "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" +); + +/// Run kzg point evaluation precompile. +/// +/// The Env has the KZGSettings that is needed for evaluation. +/// +/// The input is encoded as follows: +/// | versioned_hash | z | y | commitment | proof | +/// | 32 | 32 | 32 | 48 | 48 | +/// with z and y being padded 32 byte big endian values +fn run(input: &[u8], gas_limit: u64, env: &Env) -> PrecompileResult { + if gas_limit < GAS_COST { + return Err(Error::OutOfGas); + } + + // Verify input length. + if input.len() != 192 { + return Err(Error::BlobInvalidInputLength); + } + + // Verify commitment matches versioned_hash + let versioned_hash = &input[..32]; + let commitment = &input[96..144]; + if kzg_to_versioned_hash(commitment) != versioned_hash { + return Err(Error::BlobMismatchedVersion); + } + + // Verify KZG proof with z and y in big endian format + let commitment = as_bytes48(commitment); + let z = as_bytes32(&input[32..64]); + let y = as_bytes32(&input[64..96]); + let proof = as_bytes48(&input[144..192]); + if !verify_kzg_proof(commitment, z, y, proof, env.cfg.kzg_settings.get()) { + return Err(Error::BlobVerifyKzgProofFailed); + } + + // Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values + Ok((GAS_COST, RETURN_VALUE.to_vec())) +} + +/// `VERSIONED_HASH_VERSION_KZG ++ sha256(commitment)[1..]` +#[inline] +fn kzg_to_versioned_hash(commitment: &[u8]) -> [u8; 32] { + let mut hash: [u8; 32] = Sha256::digest(commitment).into(); + hash[0] = VERSIONED_HASH_VERSION_KZG; + hash +} + +#[inline] +fn verify_kzg_proof( + commitment: &Bytes48, + z: &Bytes32, + y: &Bytes32, + proof: &Bytes48, + kzg_settings: &KzgSettings, +) -> bool { + match KzgProof::verify_kzg_proof(commitment, z, y, proof, kzg_settings) { + Ok(ok) => ok, + #[cfg(not(debug_assertions))] + Err(_) => false, + #[cfg(debug_assertions)] + Err(e) => { + panic!("verify_kzg_proof returned an error: {e:?}"); + } + } +} + +#[inline(always)] +#[track_caller] +fn as_array(bytes: &[u8]) -> &[u8; N] { + bytes.try_into().expect("slice with incorrect length") +} + +#[inline(always)] +#[track_caller] +fn as_bytes32(bytes: &[u8]) -> &Bytes32 { + // SAFETY: `#[repr(C)] Bytes32([u8; 32])` + unsafe { &*as_array::<32>(bytes).as_ptr().cast() } +} + +#[inline(always)] +#[track_caller] +fn as_bytes48(bytes: &[u8]) -> &Bytes48 { + // SAFETY: `#[repr(C)] Bytes48([u8; 48])` + unsafe { &*as_array::<48>(bytes).as_ptr().cast() } +} + +#[cfg(test)] +mod tests { + use super::*; + + // https://github.com/ethereum/go-ethereum/blob/41ee96fdfee5924004e8fbf9bbc8aef783893917/core/vm/testdata/precompiles/pointEvaluation.json + #[test] + fn basic_test() { + let input = hex!("01d18459b334ffe8e2226eef1db874fda6db2bdd9357268b39220af2d59464fb564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a1978a0d595c823c05947b1156175e72634a377808384256e9921ebf72181890be2d6b58d4a73a880541d1656875654806942307f266e636553e94006d11423f2688945ff3bdf515859eba1005c1a7708d620a94d91a1c0c285f9584e75ec2f82a"); + let expected_output = hex!("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); + let gas = 50000; + let env = Env::default(); + let (actual_gas, actual_output) = run(&input, gas, &env).unwrap(); + assert_eq!(actual_gas, gas); + assert_eq!(actual_output, expected_output); + } +} diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 3cd41ff96d..c013b36172 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -7,9 +7,13 @@ mod blake2; mod bn128; mod hash; mod identity; +#[cfg(feature = "std")] +mod kzg_point_evaluation; mod modexp; mod secp256k1; +use alloc::{boxed::Box, vec::Vec}; +use core::fmt; use once_cell::race::OnceBox; pub use primitives::{ precompile::{PrecompileError as Error, *}, @@ -21,9 +25,6 @@ pub use revm_primitives as primitives; pub type B160 = [u8; 20]; pub type B256 = [u8; 32]; -use alloc::{boxed::Box, vec::Vec}; -use core::fmt; - pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 { (len as u64 + 32 - 1) / 32 * word + base } @@ -66,14 +67,14 @@ impl Default for Precompiles { #[derive(Clone)] pub enum Precompile { Standard(StandardPrecompileFn), - Custom(CustomPrecompileFn), + Env(EnvPrecompileFn), } impl fmt::Debug for Precompile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Precompile::Standard(_) => f.write_str("Standard"), - Precompile::Custom(_) => f.write_str("Custom"), + Precompile::Env(_) => f.write_str("Env"), } } } @@ -88,11 +89,12 @@ impl From for (B160, Precompile) { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum SpecId { - HOMESTEAD = 0, - BYZANTIUM = 1, - ISTANBUL = 2, - BERLIN = 3, - LATEST = 4, + HOMESTEAD, + BYZANTIUM, + ISTANBUL, + BERLIN, + CANCUN, + LATEST, } impl SpecId { @@ -105,9 +107,8 @@ impl SpecId { } BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM, ISTANBUL | MUIR_GLACIER => Self::ISTANBUL, - BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI | CANCUN => { - Self::BERLIN - } + BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN, + CANCUN => Self::CANCUN, LATEST => Self::LATEST, #[cfg(feature = "optimism")] BEDROCK | REGOLITH => Self::LATEST, @@ -193,6 +194,31 @@ impl Precompiles { }) } + /// If `std` feature is not enabled KZG Point Evaluation precompile will not be included. + pub fn cancun() -> &'static Self { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + // Don't include KZG point evaluation precompile in no_std builds. + #[cfg(feature = "std")] + { + let mut precompiles = Box::new(Self::berlin().clone()); + precompiles.fun.extend( + [ + // EIP-4844: Shard Blob Transactions + kzg_point_evaluation::POINT_EVALUATION, + ] + .into_iter() + .map(From::from), + ); + precompiles + } + #[cfg(not(feature = "std"))] + { + Box::new(Self::berlin().clone()) + } + }) + } + pub fn latest() -> &'static Self { Self::berlin() } @@ -203,6 +229,7 @@ impl Precompiles { SpecId::BYZANTIUM => Self::byzantium(), SpecId::ISTANBUL => Self::istanbul(), SpecId::BERLIN => Self::berlin(), + SpecId::CANCUN => Self::cancun(), SpecId::LATEST => Self::latest(), } } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index c0e76bbd21..b11858f6b3 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -10,7 +10,7 @@ version = "1.1.2" readme = "../../README.md" [dependencies] -bytes = { version = "1.4", default-features = false } +bytes = { version = "1.5", default-features = false } hashbrown = "0.14" primitive-types = { version = "0.12", default-features = false } rlp = { version = "0.5", default-features = false } # used for create2 address calculation @@ -22,6 +22,9 @@ auto_impl = "1.1" bitvec = { version = "1", default-features = false, features = ["alloc"] } bitflags = { version = "2.4.0", default-features = false } +# For setting the CfgEnv KZGSettings. Enabled by std flag. +c-kzg = { git = "https://github.com/ethereum/c-kzg-4844", default-features = false, optional = true } + # bits B256 B160 crate fixed-hash = { version = "0.8", default-features = false, features = [ "rustc-hex", @@ -32,6 +35,7 @@ hex-literal = "0.4" hex = { version = "0.4", default-features = false, features = ["alloc"] } derive_more = "0.99" enumn = "0.1" +once_cell = { version = "1.18", default-features = false } # sha3 keccak hasher sha3 = { version = "0.10", default-features = false } @@ -53,6 +57,9 @@ ruint = { version = "1.10.1", features = [ "arbitrary", ] } +[build-dependencies] +hex = "0.4" + [features] default = ["std"] dev = [ @@ -70,7 +77,7 @@ optional_block_gas_limit = [] optional_eip3607 = [] optional_gas_refund = [] optional_no_base_fee = [] -std = ["bytes/std", "rlp/std", "hex/std", "bitvec/std", "bitflags/std"] +std = ["bytes/std", "rlp/std", "hex/std", "bitvec/std", "bitflags/std", "dep:c-kzg"] serde = [ "dep:serde", "hex/serde", diff --git a/crates/primitives/build.rs b/crates/primitives/build.rs new file mode 100644 index 0000000000..161e3523be --- /dev/null +++ b/crates/primitives/build.rs @@ -0,0 +1,129 @@ +#![allow(dead_code, unused_imports)] + +use std::ffi::CString; +use std::fs; +use std::path::{Path, PathBuf}; +use std::slice; + +const BYTES_PER_G1_POINT: usize = 48; +const BYTES_PER_G2_POINT: usize = 96; + +fn main() { + generate_kzg_settings(); +} + +fn generate_kzg_settings() { + // Note: we don't use `OUT_DIR` because we don't ship this build script with the crate, so all + // used files must be in tree. + // let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + let out_dir = Path::new("src/kzg/"); + let out_path = out_dir.join("generated.rs"); + + let in_path = Path::new("src/kzg/trusted_setup.txt"); + println!("cargo:rerun-if-changed={}", in_path.display()); + assert!(in_path.exists()); + let contents = format_kzg_settings(in_path, out_dir); + fs::write(out_path, contents).unwrap(); +} + +/// Pros over `include_str!("trusted_setup.txt")`: +/// - partially decoded (hex strings -> point bytes) +/// - smaller runtime static size (198K = `4096*48 + 65*96` vs 404K) +/// - don't have to do weird hacks to call `load_trusted_setup_file` at runtime, see +/// [Reth](https://github.com/paradigmxyz/reth/blob/b839e394a45edbe7b2030fb370420ca771e5b728/crates/primitives/src/constants/eip4844.rs#L44-L52) +fn format_kzg_settings(in_path: &Path, out_dir: &Path) -> String { + let contents = fs::read_to_string(in_path).unwrap(); + let mut lines = contents.lines(); + + // load number of points + let n_g1 = lines.next().unwrap().parse::().unwrap(); + let n_g2 = lines.next().unwrap().parse::().unwrap(); + + assert_eq!(n_g2, 65); + + // load g1 points + let mut g1_points = Vec::with_capacity(n_g1); + for _ in 0..n_g1 { + let line = lines.next().unwrap(); + let mut bytes = [0; BYTES_PER_G1_POINT]; + hex::decode_to_slice(line, &mut bytes).unwrap(); + g1_points.push(bytes); + } + + // load g2 points + let mut g2_points = Vec::with_capacity(n_g2); + for _ in 0..n_g2 { + let line = lines.next().unwrap(); + let mut bytes = [0; BYTES_PER_G2_POINT]; + hex::decode_to_slice(line, &mut bytes).unwrap(); + g2_points.push(bytes); + } + + assert!(lines.next().is_none()); + + fs::write(out_dir.join("g1_points.bin"), into_flattened(g1_points)).unwrap(); + fs::write(out_dir.join("g2_points.bin"), into_flattened(g2_points)).unwrap(); + + format!( + r#"// @generated by build.rs from {in_path:?}, do not modify manually. + +pub use c_kzg::{{BYTES_PER_G1_POINT, BYTES_PER_G2_POINT}}; + +// Ensure that the build script constants are synced with the C bindings ones. +const _: [(); BYTES_PER_G1_POINT] = [(); {BYTES_PER_G1_POINT}]; +const _: [(); BYTES_PER_G2_POINT] = [(); {BYTES_PER_G2_POINT}]; + +pub const NUM_G1_POINTS: usize = {n_g1}; +pub const NUM_G2_POINTS: usize = {n_g2}; + +type G1Points = [[u8; BYTES_PER_G1_POINT]; NUM_G1_POINTS]; +type G2Points = [[u8; BYTES_PER_G2_POINT]; NUM_G2_POINTS]; + +pub const G1_POINTS: &G1Points = {{ + const BYTES: &[u8] = include_bytes!("./g1_points.bin"); + assert!(BYTES.len() == core::mem::size_of::()); + unsafe {{ &*BYTES.as_ptr().cast::() }} +}}; +pub const G2_POINTS: &G2Points = {{ + const BYTES: &[u8] = include_bytes!("./g2_points.bin"); + assert!(BYTES.len() == core::mem::size_of::()); + unsafe {{ &*BYTES.as_ptr().cast::() }} +}}; +"# + ) +} + +/// [`Vec::into_flattened`]. +#[inline] +fn into_flattened(vec: Vec<[T; N]>) -> Vec { + let (ptr, len, cap) = into_raw_parts(vec); + let (new_len, new_cap) = if core::mem::size_of::() == 0 { + (len.checked_mul(N).expect("vec len overflow"), usize::MAX) + } else { + // SAFETY: + // - `cap * N` cannot overflow because the allocation is already in + // the address space. + // - Each `[T; N]` has `N` valid elements, so there are `len * N` + // valid elements in the allocation. + unsafe { + ( + len.checked_mul(N).unwrap_unchecked(), + cap.checked_mul(N).unwrap_unchecked(), + ) + } + }; + // SAFETY: + // - `ptr` was allocated by `self` + // - `ptr` is well-aligned because `[T; N]` has the same alignment as `T`. + // - `new_cap` refers to the same sized allocation as `cap` because + // `new_cap * size_of::()` == `cap * size_of::<[T; N]>()` + // - `len` <= `cap`, so `len * N` <= `cap * N`. + unsafe { Vec::from_raw_parts(ptr.cast(), new_len, new_cap) } +} + +/// [`Vec::into_raw_parts`] +#[inline(always)] +fn into_raw_parts(vec: Vec) -> (*mut T, usize, usize) { + let mut me = core::mem::ManuallyDrop::new(vec); + (me.as_mut_ptr(), me.len(), me.capacity()) +} diff --git a/crates/primitives/src/bits.rs b/crates/primitives/src/bits.rs index 45ac577d8c..440c3029ee 100644 --- a/crates/primitives/src/bits.rs +++ b/crates/primitives/src/bits.rs @@ -1,4 +1,4 @@ -#![allow(clippy::incorrect_clone_impl_on_copy_type)] +#![allow(clippy::non_canonical_clone_impl)] use derive_more::{AsRef, Deref}; use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions}; diff --git a/crates/primitives/src/bytecode.rs b/crates/primitives/src/bytecode.rs index f8a0a70601..5701654f58 100644 --- a/crates/primitives/src/bytecode.rs +++ b/crates/primitives/src/bytecode.rs @@ -38,11 +38,15 @@ impl JumpMap { } } +/// State of the [`Bytecode`] analysis. #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum BytecodeState { + /// No analysis has been performed. Raw, + /// The bytecode has been checked for validity. Checked { len: usize }, + /// The bytecode has been analyzed for valid jump destinations. Analysed { len: usize, jump_map: JumpMap }, } @@ -156,10 +160,11 @@ impl Bytecode { match self.state { BytecodeState::Raw => { let len = self.bytecode.len(); - let mut bytecode: Vec = Vec::from(self.bytecode.as_ref()); - bytecode.resize(len + 33, 0); + let mut padded_bytecode = Vec::with_capacity(len + 33); + padded_bytecode.extend_from_slice(&self.bytecode); + padded_bytecode.resize(len + 33, 0); Self { - bytecode: bytecode.into(), + bytecode: padded_bytecode.into(), state: BytecodeState::Checked { len }, } } diff --git a/crates/primitives/src/constants.rs b/crates/primitives/src/constants.rs index 6fa8affd07..7776b18d04 100644 --- a/crates/primitives/src/constants.rs +++ b/crates/primitives/src/constants.rs @@ -19,3 +19,15 @@ pub const MAX_INITCODE_SIZE: usize = 2 * MAX_CODE_SIZE; /// Precompile 3 is special in few places pub const PRECOMPILE3: B160 = B160([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]); + +// EIP-4844 constants +/// Maximum consumable blob gas for data blobs per block. +pub const MAX_BLOB_GAS_PER_BLOCK: u64 = 6 * GAS_PER_BLOB; +/// Target consumable blob gas for data blobs per block (for 1559-like pricing). +pub const TARGET_BLOB_GAS_PER_BLOCK: u64 = 3 * GAS_PER_BLOB; +/// Gas consumption of a single data blob (== blob byte size). +pub const GAS_PER_BLOB: u64 = 1 << 17; +/// Minimum gas price for data blobs. +pub const MIN_BLOB_GASPRICE: u64 = 1; +/// Controls the maximum rate of change for blob gas price. +pub const BLOB_GASPRICE_UPDATE_FRACTION: u64 = 3338477; diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 9d883f6b0f..ec4a470904 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -1,6 +1,6 @@ use crate::{ - alloc::vec::Vec, Account, EVMError, InvalidTransaction, Spec, SpecId, B160, B256, KECCAK_EMPTY, - MAX_INITCODE_SIZE, U256, + alloc::vec::Vec, calc_blob_fee, Account, EVMError, InvalidTransaction, Spec, SpecId, B160, + B256, GAS_PER_BLOB, KECCAK_EMPTY, MAX_INITCODE_SIZE, U256, }; use bytes::Bytes; use core::cmp::{min, Ordering}; @@ -12,22 +12,46 @@ pub struct Env { pub block: BlockEnv, pub tx: TxEnv, } + +/// The block environment. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BlockEnv { + /// The number of ancestor blocks of this block (block height). pub number: U256, /// Coinbase or miner or address that created and signed the block. - /// Address where we are going to send gas spend + /// + /// This is the receiver address of all the gas spent in the block. pub coinbase: B160, + /// The timestamp of the block in seconds since the UNIX epoch. pub timestamp: U256, - /// Difficulty is removed and not used after Paris (aka TheMerge). Value is replaced with prevrandao. + /// The gas limit of the block. + pub gas_limit: U256, + + /// The base fee per gas, added in the London upgrade with [EIP-1559]. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + pub basefee: U256, + + /// The difficulty of the block. + /// + /// Unused after the Paris (AKA the merge) upgrade, and replaced by `prevrandao`. pub difficulty: U256, - /// Prevrandao is used after Paris (aka TheMerge) instead of the difficulty value. - /// NOTE: prevrandao can be found in block in place of mix_hash. + /// The output of the randomness beacon provided by the beacon chain. + /// + /// Replaces `difficulty` after the Paris (AKA the merge) upgrade with [EIP-4399]. + /// + /// NOTE: `prevrandao` can be found in a block in place of `mix_hash`. + /// + /// [EIP-4399]: https://eips.ethereum.org/EIPS/eip-4399 pub prevrandao: Option, - /// basefee is added in EIP1559 London upgrade - pub basefee: U256, - pub gas_limit: U256, + + /// Excess blob gas. See also [`calc_excess_blob_gas`](crate::calc_excess_blob_gas). + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + pub excess_blob_gas: Option, } #[cfg(feature = "optimism")] #[derive(Clone, Debug, Default, PartialEq, Eq)] @@ -46,37 +70,124 @@ pub struct OptimismFields { pub enveloped_tx: Option, } +impl BlockEnv { + /// See [EIP-4844] and [`Env::calc_data_fee`]. + /// + /// Returns `None` if `Cancun` is not enabled. This is enforced in [`Env::validate_block_env`]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + #[inline] + pub fn get_blob_gasprice(&self) -> Option { + self.excess_blob_gas.map(calc_blob_fee) + } +} + +/// The transaction environment. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TxEnv { - /// Caller or Author or tx signer + /// The caller, author or signer of the transaction. pub caller: B160, + /// The gas limit of the transaction. pub gas_limit: u64, + /// The gas price of the transaction. pub gas_price: U256, - pub gas_priority_fee: Option, + /// The destination of the transaction. pub transact_to: TransactTo, + /// The value sent to `transact_to`. pub value: U256, + /// The data of the transaction. #[cfg_attr(feature = "serde", serde(with = "crate::utilities::serde_hex_bytes"))] pub data: Bytes, - pub chain_id: Option, + /// The nonce of the transaction. If set to `None`, no checks are performed. pub nonce: Option, + + /// The chain ID of the transaction. If set to `None`, no checks are performed. + /// + /// Incorporated as part of the Spurious Dragon upgrade via [EIP-155]. + /// + /// [EIP-155]: https://eips.ethereum.org/EIPS/eip-155 + pub chain_id: Option, + + /// A list of addresses and storage keys that the transaction plans to access. + /// + /// Added in [EIP-2930]. + /// + /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930 pub access_list: Vec<(B160, Vec)>, + + /// The priority fee per gas. + /// + /// Incorporated as part of the London upgrade via [EIP-1559]. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + pub gas_priority_fee: Option, + + /// The list of blob versioned hashes. + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + pub blob_hashes: Vec, + /// The max fee per blob gas. + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + pub max_fee_per_blob_gas: Option, + #[cfg_attr(feature = "serde", serde(flatten))] #[cfg(feature = "optimism")] pub optimism: OptimismFields, } +impl TxEnv { + /// See [EIP-4844] and [`Env::calc_data_fee`]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + #[inline] + pub fn get_total_blob_gas(&self) -> u64 { + GAS_PER_BLOB * self.blob_hashes.len() as u64 + } +} + +/// Transaction destination. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TransactTo { + /// Simple call to an address. Call(B160), + /// Contract creation. Create(CreateScheme), } impl TransactTo { + /// Calls the given address. + #[inline] + pub fn call(address: B160) -> Self { + Self::Call(address) + } + + /// Creates a contract. + #[inline] pub fn create() -> Self { Self::Create(CreateScheme::Create) } + + /// Creates a contract with the given salt using `CREATE2`. + #[inline] + pub fn create2(salt: U256) -> Self { + Self::Create(CreateScheme::Create2 { salt }) + } + + /// Returns `true` if the transaction is `Call`. + #[inline] + pub fn is_call(&self) -> bool { + matches!(self, Self::Call(_)) + } + + /// Returns `true` if the transaction is `Create` or `Create2`. + #[inline] pub fn is_create(&self) -> bool { matches!(self, Self::Create(_)) } @@ -95,12 +206,17 @@ pub enum CreateScheme { }, } +/// EVM configuration. #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] pub struct CfgEnv { pub chain_id: u64, pub spec_id: SpecId, + /// KZG Settings for point evaluation precompile. By default, this is loaded from the ethereum mainnet trusted setup. + #[cfg_attr(feature = "serde", serde(skip))] + #[cfg(feature = "std")] + pub kzg_settings: crate::kzg::EnvKzgSettings, /// Bytecode that is created with CREATE/CREATE2 is by default analysed and jumptable is created. /// This is very beneficial for testing and speeds up execution of that bytecode if called multiple times. /// @@ -213,25 +329,31 @@ impl CfgEnv { } } +/// What bytecode analysis to perform. #[derive(Clone, Default, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AnalysisKind { + /// Do not perform bytecode analysis. Raw, + /// Check the bytecode for validity. Check, + /// Perform bytecode analysis. #[default] Analyse, } impl Default for CfgEnv { - fn default() -> CfgEnv { - CfgEnv { + fn default() -> Self { + Self { chain_id: 1, spec_id: SpecId::LATEST, - perf_analyse_created_bytecodes: Default::default(), + perf_analyse_created_bytecodes: AnalysisKind::default(), limit_contract_code_size: None, disable_coinbase_tip: false, + #[cfg(feature = "std")] + kzg_settings: crate::kzg::EnvKzgSettings::Default, #[cfg(feature = "memory_limit")] - memory_limit: 2u64.pow(32) - 1, + memory_limit: (1 << 32) - 1, #[cfg(feature = "optional_balance_check")] disable_balance_check: false, #[cfg(feature = "optional_block_gas_limit")] @@ -249,32 +371,35 @@ impl Default for CfgEnv { } impl Default for BlockEnv { - fn default() -> BlockEnv { - BlockEnv { - gas_limit: U256::MAX, + fn default() -> Self { + Self { number: U256::ZERO, coinbase: B160::zero(), timestamp: U256::from(1), + gas_limit: U256::MAX, + basefee: U256::ZERO, difficulty: U256::ZERO, prevrandao: Some(B256::zero()), - basefee: U256::ZERO, + excess_blob_gas: Some(0), } } } impl Default for TxEnv { - fn default() -> TxEnv { - TxEnv { + fn default() -> Self { + Self { caller: B160::zero(), gas_limit: u64::MAX, gas_price: U256::ZERO, gas_priority_fee: None, - transact_to: TransactTo::Call(B160::zero()), //will do nothing + transact_to: TransactTo::Call(B160::zero()), // will do nothing value: U256::ZERO, data: Bytes::new(), chain_id: None, nonce: None, access_list: Vec::new(), + blob_hashes: Vec::new(), + max_fee_per_blob_gas: None, #[cfg(feature = "optimism")] optimism: OptimismFields::default(), } @@ -282,26 +407,39 @@ impl Default for TxEnv { } impl Env { + /// Calculates the effective gas price of the transaction. + #[inline] pub fn effective_gas_price(&self) -> U256 { - if self.tx.gas_priority_fee.is_none() { - self.tx.gas_price + if let Some(priority_fee) = self.tx.gas_priority_fee { + min(self.tx.gas_price, self.block.basefee + priority_fee) } else { - min( - self.tx.gas_price, - self.block.basefee + self.tx.gas_priority_fee.unwrap(), - ) + self.tx.gas_price } } - /// Validate ENV data of the block. + /// Calculates the [EIP-4844] `data_fee` of the transaction. /// - /// It can be skip if you are sure that PREVRANDAO is set. + /// Returns `None` if `Cancun` is not enabled. This is enforced in [`Env::validate_block_env`]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + #[inline] + pub fn calc_data_fee(&self) -> Option { + self.block + .get_blob_gasprice() + .map(|blob_gas_price| blob_gas_price * self.tx.get_total_blob_gas()) + } + + /// Validate the block environment. #[inline] pub fn validate_block_env(&self) -> Result<(), EVMError> { - // Prevrandao is required for merge + // `prevrandao` is required for the merge if SPEC::enabled(SpecId::MERGE) && self.block.prevrandao.is_none() { return Err(EVMError::PrevrandaoNotSet); } + // `excess_blob_gas` is required for Cancun + if SPEC::enabled(SpecId::CANCUN) && self.block.excess_blob_gas.is_none() { + return Err(EVMError::ExcessBlobGasNotSet); + } Ok(()) } @@ -369,11 +507,29 @@ impl Env { } } - // Check if access list is empty for transactions before BERLIN + // Check that access list is empty for transactions before BERLIN if !SPEC::enabled(SpecId::BERLIN) && !self.tx.access_list.is_empty() { return Err(InvalidTransaction::AccessListNotSupported); } + // - For CANCUN and later, check that the gas price is not more than the tx max + // - For before CANCUN, check that `blob_hashes` and `max_fee_per_blob_gas` are empty / not set + if SPEC::enabled(SpecId::CANCUN) { + if let Some(max) = self.tx.max_fee_per_blob_gas { + let price = self.block.get_blob_gasprice().expect("already checked"); + if U256::from(price) > max { + return Err(InvalidTransaction::BlobGasPriceGreaterThanMax); + } + } + } else { + if !self.tx.blob_hashes.is_empty() { + return Err(InvalidTransaction::BlobVersionedHashesNotSupported); + } + if self.tx.max_fee_per_blob_gas.is_some() { + return Err(InvalidTransaction::MaxFeePerBlobGasNotSupported); + } + } + Ok(()) } @@ -408,11 +564,18 @@ impl Env { } } - let balance_check = U256::from(self.tx.gas_limit) + let mut balance_check = U256::from(self.tx.gas_limit) .checked_mul(self.tx.gas_price) .and_then(|gas_cost| gas_cost.checked_add(self.tx.value)) .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; + if SpecId::enabled(self.cfg.spec_id, SpecId::CANCUN) { + let data_fee = self.calc_data_fee().expect("already checked"); + balance_check = balance_check + .checked_add(U256::from(data_fee)) + .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; + } + // Check if account has enough balance for gas_limit*gas_price and value transfer. // Transfer will be done inside `*_inner` functions. if !self.cfg.is_balance_check_disabled() && balance_check > account.info.balance { diff --git a/crates/primitives/src/kzg.rs b/crates/primitives/src/kzg.rs new file mode 100644 index 0000000000..8106f19fc8 --- /dev/null +++ b/crates/primitives/src/kzg.rs @@ -0,0 +1,9 @@ +mod env_settings; +#[rustfmt::skip] +mod generated; + +pub use c_kzg::KzgSettings; +pub use env_settings::EnvKzgSettings; +pub use generated::{ + BYTES_PER_G1_POINT, BYTES_PER_G2_POINT, G1_POINTS, G2_POINTS, NUM_G1_POINTS, NUM_G2_POINTS, +}; diff --git a/crates/primitives/src/kzg/env_settings.rs b/crates/primitives/src/kzg/env_settings.rs new file mode 100644 index 0000000000..ecf760c0a2 --- /dev/null +++ b/crates/primitives/src/kzg/env_settings.rs @@ -0,0 +1,36 @@ +use super::{ + generated::{G1_POINTS, G2_POINTS}, + KzgSettings, +}; +use alloc::{boxed::Box, sync::Arc}; +use once_cell::race::OnceBox; + +/// KZG Settings that allow us to specify a custom trusted setup. +/// or use hardcoded default settings. +#[derive(Debug, Clone, Default, Eq, PartialEq)] +pub enum EnvKzgSettings { + /// Default mainnet trusted setup + #[default] + Default, + /// Custom trusted setup. + Custom(Arc), +} + +impl EnvKzgSettings { + /// Return set KZG settings. + /// + /// In will initialize the default settings if it is not already loaded. + pub fn get(&self) -> &KzgSettings { + match self { + Self::Default => { + static DEFAULT: OnceBox = OnceBox::new(); + DEFAULT.get_or_init(|| { + let settings = KzgSettings::load_trusted_setup(G1_POINTS, G2_POINTS) + .expect("failed to load default trusted setup"); + Box::new(settings) + }) + } + Self::Custom(settings) => settings, + } + } +} diff --git a/crates/primitives/src/kzg/g1_points.bin b/crates/primitives/src/kzg/g1_points.bin new file mode 100644 index 0000000000000000000000000000000000000000..de9e103f081627292024aac9aa909204783467f7 GIT binary patch literal 196608 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
bq?zV>7t>EFE{;$s#^oL>Obr<_PqodLG{nT! z15O+KCrr@CN`la>lf?)E-qGR`7p04bOb1S-BO*yHSePJb6>DB7@M5v2MtqqRD)E{XI?|>eN zxZ-TQgZiLT`XqiP$z2<}ca>W+ZW|6k(12qyNF$Btt;xBDh{=!N#(r{!yj$dnpJ{?T z@v7`9r`>lrcB3iyTJbV3D3Pc)cQ~W}tbdZe!RS1v6}PF8$JtfBV3+dNM$a zo``2^#Q1iD&o{$;AwgrxV+!moJirv#jIZ-hBL6#W18%r9JyN5$b`K}p2Lz^cC{>w? z3^6l1vrS;#>&aD!;#+b=TH*r)C#tZB>;gZORxucu4?A?N2JFD|bXZ}+X1|m03oz6k z*quS?nzldf*Okd|)2%>O4p*ylGl)8JAbe1gEGVGy?=8|j%u2+^MufKg4hW&Vy81=iU8BK6zQ`iDW`zp?>MKb`luZ-hc^?uZzR>BYZzKXaD-NlJ z@BDQob!?%xxgbHVGBY<}izAPfhcTw{h#zGwGzcG!uK zOLo(WaAoQnEZ(R)7^P3GxeNav4Shwpx+t|az~J}v+)J7RRB0~HDN~j)*QI?hjkDx9 z;Q0rE0yM;sv>{Wa7>svX*Jc;fyKa9UJ0wZ;i+i`IKsCb_C_|P~m1LqPbZUBpEx9}VP)ae-REHCkaLQU#Pt)?v18`ZvwbWG8(j(s8EZNge^_y}@o&PR6F@q({2OYT{ocoW=Rjl=w+`VZ z@aRXD7K&FXKvfN4fX_s37HC@m^wSECyLee-g8c|wps-CXh4aS_}t#Uijz z<9wBaw^ZXq_m#7bszpLq_j+ekvcbjw05z>vkSue5%kr49d0Rup0B#tG zPn92Ee9{Au7(d>wEaIY-rDytKxtFo|bYkD>1a zai3I*zQ^+)Yl(UtNponVCo`tK6#u)6A=Bia#LYZ_EvF8MhJt(=>I)drv_>`f9>ig$ z(dPXmu!oQGWVa<|E=ZJ7#gMY9+VfY|LJ*^HALnEBDS~gN;8jv*!S(FI#ViGn=F+6< z4UupxvZ$fh0`*ysCfJhksVV;jZ7Y(9A>^@g!NI^#TB1dPKjv_B&zLlVpeCdU05yXH zZx$wj6Uty`&J*aIZkq6?VDz#`7*WPAt?us)HXl*k+4@#=>{n2viKTS7V$=m-k?&&; z2%Hu?7Q*oa*h-tQe`$Kq?aC<&f4R-U;xdt5VOA8Y`#!4AMf^caFf+`Zy_I z$-P@gYq8Bl{}eEzha0=jprG3(FvFhaIsG2DVwDNl!=t#1G4ZbxdL_e;Q(}bi8e6;I z&|8M6YsoIV_YW7sR@{pXNH(W%@)t=YcESF~k1ESI{h#IkM zSa*{#gLNsEU(^>tpxBtg@&t)Rvab9|$2B61CEl+W{@5%{QqMn*le7DXC9UQ%+(|$& z8x=yi^Z=sA%6+J_WN_|XCdP8LDY=eif&nbQ!lS}Va_2u*Gu}dF#23KSd`Cf5rUS-> z^E0rqV+v@BIA2J=0d>t2?A?<3RGCRnO4Y8Q?;D*M53P@rU>H-4geEZma)?ZgsakVd z8kp^lRxp{phtWDCeb?-0fX}Q}#zAWU9+)~-^Vcofe`sh+vp!E`%H1%cn`WX3UK-5j zQTDFL-|FGzvO$O6?X}TkT&Uiz8MT1#2{M`(vp8P65q#GcarE7=0p9MfUay&~Rg7R~ zduDr|Jy*{|qQupI*Gm#wZKp1#$=rdl5M^Es@EoVOr>E_aE)n1VcgJ{^m^Re{mq)ae z-GSNpW%#}p+gqIAn|Vls$n z{*n(?GNzhcFxb=1KMYid%QZn|c08mVgGpMqP4yYB8jr63EX^s2D2B5q$3sJ4t6Wo6 zbtY#9ns?M@q>QzD8Boy+Y)8n8DupU(`Z?NF^1`NQ_p)!eC692$MN1RnNIp8$ zQuC~Q#QFzUgXb$s5**f(iZyhqVD;d*O9Yi`g`z4oZiP5Ff zkeW}#F6bJVtqItcy^yJ($gI|)@YJgg3TO|crh5l#yYwrb#S-fTz6JXxCHB(odqYX? zzG3U1d(`+|o#*<6#wpGX?zdbRqp`H%MR&DkZ1Pl7sGTSA0-7m=6FMu7cV=0BFZu2! zrdCO~7Pe56jk`y9K-29f`2*0O*_EGf>_k7jlQK)fg8be) zoLX$B$86N3Dz}hL18?SIbaB~(YSCQ{CZKy51GoE$h`7n^^&;TYH=%_gG0^r{R$AwS ziZCV&^Fgi**Qwux%fn+-#=LuvP{~~tL{rJ=>{KJow^g~1hYKHh zj0G09c_%zrJSJ=)Ah_PA=8NR8VvB_Zok``UfN-2WY^uI?dJhAaTt+5|y3n>soo5?1 zD(IO0<4V$ns*HEjJfYTZkA=0?H@nxaAw|lreV<3^OeN{jYm85?mOVYw*@K2mRIu$7 zDa9*BV}tN|6$Bw$znP2&8VQ;@9qS0$OH^YD$88-z&%@faXl>#L!`2N=&*q^Cz_Rm0 z?H;#p z`iNQdYJ+!R-{mQyLhI91EstJlEuas)|z zc$>*d(e*wy%JYU0(e2V7UY<2oge?mDP~R9NB@z;%bb6F zCC;S>@G)nzOnoH!R;y~wxUXAJrj((WS{FggQ=+iNgEkT9?QgTTW2D)kCc8=+MxP*Z z8J%W}j=LjwO6v4slugTf^arGESW;F7h215vGy=b2w3fu@$P*q=Mc zggPEYtd<^0!Iu#f#UqWLA!K+2v4ty-M{0?|Egs*wfB$hrUWc7){X1}x9gFNuOg?j> z!&GUq7IkU$mjysXCB2nI1PJ?hjuJ1H>9M_OUp2 zS=)aWPKh-dbU((G*@wuFiTo)OZaiMN8Ds6M^0x8?aUi~O z&3qEha}%iEXScmH_|AHz z9Rt0FL-M>P7QuUH)Bb!9vt$!#CZT4vQUI=fZo3Nvw@3vXSqCXGgs~>iiX1OBegaP# zV)hQz7uvCxGX{w}4nGM9nIQoJ=i%=5 z_s#P3;N{zrBgQ0Zqad-fZn5HvU!2S-cj!lj31sCM{P1 zVz;BN?$R5RCsJ^qL);83eJ9caW4UTn7hTqMXL>-Olkh9Lfa2y_{ywrNGN)mC^#7f- ze6Cmu=ub{V1KW>iPgRqG@OAHQm1&EbVxE$=d+-GIPJHx!Ko@BG7YssK@4cafm?7cn z*dOBDNzGaEyQ2kHj835F^ti5%!gZm(;9DAgk#C2%-#;ACdpeFf$Moj zhGjWi4pj&#tNr?hXqK7Pcrb--GC-1~Bl0nmL0Z$NGC_RGmvOLG?LympJtq6ca$0mIfE36QjC@*d=;%hBaDgC5c0-af3l-y<$$O zI|}e&c<5y~;y3t@&^hYQe6UK06Ez?TNOeWyjawi6qX-PIS1IASfM7e#`RZjX>Uc;q zTZ69Zqao8rYUHTd2Q`ATo`k_hX4M##x2QB9*fF1;3RtqG55w1zT+T2z_s3IbwfkH0 zU-WVenUc!4xViL>q`I^&bvzGqa9ddnrEk zGWf>~?;hE{e=+tATT?D&-+d^BAUo%ade@4x0UO0k+4f9$oA@`Sq`;}L;I_MwEcWcv z2RN{-z!YtFL?lVHhQsqMeqba|WI9~=%x$9HR0z<;@ph4@AL}xowHtCqOWn`UP68C2 znOjtih{j8yLljKmYh^5%6UgqAj_5a8ZpnPaJ&ehS<)`U7bB$p$1SPy7t>}$2*A@*D zOYwB;J`$h;gJnc918H}}@uYeiyYlaZNvw&ib*+2}lY<7HW-I+RB)KbOwS$62kS-Q~ z!yA+l@7js7#=Fth8=kk*1p2J>IM)k>gS^ql%bT>jYtQ%tu&I%eD})24JPnz5VgGk2 zT+B6n0+KO?0jS0kDXS>{*SmwE`KkpY@!#+OBcw`fI-X7vJK*+mDja5ltUO>x@9E|* zM|0Zrc7BCUAItdeb2;LL_Fla8$K`YvOMFa0W~rq%j(LW-!0&`?E)%z1>T?mObc0Ya zN$dMOxH+@$HOMWi#a`=jX^=6aXSruuE0L%}P9FhAc3_Y^?L(llp&Etj-$?mf6aQ!A z;+249r4RF@|98o_X*r=*M@gHM5IOZx>LTk?A~IVvTJU92g4y}b8Rq`qe<|FLW7 zB%=SX4MD+MQF8C70nCN%5F2)cP0a>zEe#^OTAFDoJQh*HBNt8ZuSqBToYXxxO^Ly@_sHCltK>_MgP`vPAS?@UaIBX2 zfD>LKR{i*vO|Dw)UC{PLDs7GuGa=}~g0re`ABwkU%BMBCEwKzC!y(TTN&PeuopFHW z2#v2RzE=(ALUNg^wuzF!5yIk=nnWaXmi0n>9g#|v&KQ!>&L!_F$ciI~09B;eDWkI= zI0j>1)SK)w%%tgMu_?CQK9Kk0qU$L?{8WvX4EPrAbpfs8YYSQUe10`4SN4A&b-S$C z?NW(9pTq@n$8Sl(J+w$>uYNS9Jk$B2{LqDg(^jAVX`k2a9^PM=^0`@7?BADKDX#@R zpHD(y3pN(5VPWZ5!_Ht6oFJsIGH8oz$fxE#%Ytc7aqx$+?sUY}`X@3w9<4i~7b4gE zN$sa)a$8kX+frZvP)WnEx1K{O@vSBAYG5;vy7-B8e5+dV3;JnOrXPu_tl&f|p74%W zx_6Hrm%k$MZwk($=Bx(zmojF}4fIF&EbJCxP4-cA$5!BfQ9djgs)E4{hHwOUV3rK~ zqs8RJCuqol9%kPUHzA>}0+Upl4m{V1`9HS4EUS(d0a|TRNGkaSdmDA>MPnkRspxVw z;3Un5M5qfro;TV|P{lR?d4Z&rjeb)cxj7cw`Gw8GFHiJ>rOZ#|2^GLe(%xoM4;X>6 z3vP^i=2XHwjHE!mEH}@b$@J(S?%&YOd{*;*+K(w;<21e6?i?Ytj@thl4>Uq^dw zM9oS0;E}v5_sQSxhiu*w2U>l(CL9U^O? za4rIr*vR4RNa&V$?6BrYHndU&p&*D~sQ9C#xzw<+A7QaDC3&F`ce^hi4YP5plr?j* zVZJDh$6<2r=%o-VnJQaSV3N^b|I!MqEl5_YNgsb604hY3OafDXHeOO*yKPn!yQt;p z=)DpKOmHd}Syvs~?&Xr8x{Gtq&WI3+AswUHD(!0#9pC}DwW%W-94!g^9MWNq#8@kPSKi- zMI5P%@86p(i(ing%cDAH_GAHJPV8T)MdxGMC{Ej*#}m5LtOJ)OFnAgXqvE2Gs=#1c zm0-p5L`~(23ZXI!^&xr$n*yx@r1+A*)}!^bk4GRu(JwlxxZN3Z2k}Jt-d~<}ENe+| zp&_)S5(-wHL~rC0pP7zP@SGgSvYo=SQ`YwIU8>Qf@0qOpx}=o~SgOx{;j{hVuQSlE z_Y-i{ixgK_rSeSkz{X~MBBA+ExD$LfpQuHpCS2A@T%%NeFgz?Iw<6PPf zJvQVz|2^2xMWv-5!%DBCraseDFh{zbYVxVPd>|YGgqh~F#2YAt-LrJX$rlL&yFL(9 z`p|K(p+~98F1|0@Nglf-G1WUch;pNx!-e^Cg!U)wV`U}iTYaM zSVr>E^I2+AHyhY!7#UzVBJPbctBl$k)hP{N9!NiwYiY_;VYUoC!yU0UX|P^g1XA}HH6EVWJIh>c(nFrjM3CdCeI^Q-^j9Jp#0~gwn@jHt_<<)NviBi^bD*lQ zj7?2Xv5F6{?`x^Qf2BMTY{v0tLgY`2z~~a#w;0>xj;(a2ynC!@iG2akmqIJxK@g%< ziMq{D(>Bt`w+#*b=E1nUH!Z`7T@j70FSA-p4dN@{&;aZY4>5a`l-qm~@eO^r8*e_Z zZEru{=~DP^#1uVrX*P|CJM-7&dFTLAYr_{qifLI5Gj*9UgAK2iTrD$$%Hb3d0zJt~7F3wFvAq02vrELQo_fE%mpy z*r8by>lYLT9bBxv3$R|@gY4Uciix;n=Rp;i>Gy$63RuygK*OS7&lR=U+vC= zQLdaM*ZKzQ#m!DS?}x9i1g8}aRvK!5BS*c?!R2d$*5&n={&6Js%uqXpCIC#J$O5o) z)e8v%>S>o*N#|C3E?LSf^dP)b*%?vNV3zW$uzD#~r4z#l$CMUzl5gpe}_#nf$hUi@d=GG z8coXCq$V=6mNWSI(h52CN+e{XDC(??7%B>3JYgE=w1RwInV*x6?FNz@0+hb}!W{zUjRRUQ z$k053WDzE&iH(pZUC$4)6=I(RuzYzK;38&qgYV$K;4dYML}^rqY;39HY5(E72c9Do z>)JAsFU2loi)$-qXux^KdbB0la*%pPt=Iu^Uy3C+C^nk&+w#rT zf&M#zu~vB^DC*)!R}kjH9o795VNJt9y9)d3ybm%o4%(jyOJfTB{1@nudI??1h+U!? z@t#uY}q0SRNjCi2*=y_+ufA0Rg2bP8g8Ap7m7s6T|3k`3>mio5)xva8=K8 zL-mr(PTd(l1NR*k$uIzy-LJQoQpP_MT!>7OGGzRy07iT6SfnZ8@b*yBe#X2BLaLk^sR)iJ;l=9DOO$R^v3|z@vCv#+e18UX>>8nGQ-Q|2+3dmh&CL0;2=6P0Lya|+agixU zg6Z`EN;8!D+SB69uWr8}{fL@2+qm7cV@s-zE)y0Qs!ni`o|i6LXU%2vcj-6Qd?&Qs zZ`3UQIZ8CA4vZx_86x&C^J|^Vf4jn)31F>if8L0oFdFlUkqL3gIUe)uf-K`# zS0ZYE*=beHd9R^L%(_TU^yddYMzpd(rG`J0BKFiI!ErYS@SUWQ`CMgtkz z#D{wxa9X9!i)%WOCWB+_I9I`iXkSaW&z~Su5uGSXH{VV~iMBFXP4-S*$VO!@;%i40 z<5K1`F&MEW0u+H0j!whr`IvjIse|Yof;4j9hEioq=%xyb^Z`fJnfQJ(Gnepd_>7q8 z#@i1lK~HX^2_HVN_Ni^EAio36i*Nm)pWyFlKftP^yEi5S=Z0_&QU*Fte&<4W96`@s zXXYf2nYa9N_Km-XNTip6mWvKu zEuZ?Uv7=d1+=_JF9NWmQa+Jou(UA_?w(wkso}SQbV``M2-~oQde~)i-@BFoae9W$k z??XZ>99iR3xAbfXsOxy*Y)t{eHl+S|9PhVAQj?@aPb=JL#-bt3SXv~M*`e2yQgT?7 z5AXIH@1c*)W+wdq0i86Xtc+-eS)9K2TNS}wXr7E4(ieQmJWLmo-sso2@f7Z_DoSBfOIMmsT~AsboeKiy2A^YT7P0 z$fRE|7sEg__g5reZ#$UAT{+N%=S?b|!g1x1kE&Cd4#q#Oq^+Q+Q*}MCKbMf=3#)+9 z2Klg_l@AH7tEJd!@E1GnXFG;!me#P{fg`0k%B-5WBm`FynKlzR6op~kCaeEx5MD`+^Z5E=5hwp)>QWJ?z5#TWni>43YZYw5C#uioO zwHx#t$ivpb29{(lqfvKo`8(raAa)^*PXBW?B`u z*VOfrPO3^CF`!P2#v^8jOZasVXQd|UGLm(K&h!y<;_O;e2cG3u27AJS^K!T`%Oyv} z;up4ucYqckj)>0E0SGXo>j@s(XTIs zo2Q5HQqyKsfy3Qc6`sh#IN2EcZ6}B8;&tzu%{P3vs-QY)f(&>hd-WRrnKUzSpHasx$*5_0lqjZ39|cF1*z z7?xgWNtYgimbMT0T2e3Ws-x09HkQCZ*uAeCI1RIs>4>U@04p)hF}{4rb#XzZntb^p zi-QzNlhY-#Bp+M)z?uTApu;vWa#!)Gc)+{&pQQe|Ytm|KyT=8_Kqz0;VU#}hS^TFz zCFs8>&&?qjS5mYCS~k+h#yC7g|GPuCSCa$V8$TZe^)2K+zg;7F`UxS~6w z@Uf74d<_g<_WE|s+#~Rptfrlgi0zF=jZ=??K4MR5?S?{3YkGzrKSjvDN5DRN71Le; z_pQ*R6?*Y;*)|Ndkl2>yw({iM|Lgi^{0M)g7^%q12sEW;jH~2MTq|!Rk1(5@*GG8+ z4i_!DU7jhI=LwttWlPI9uu-GvrKe{tYPab(N2z-TFUPI`$zAUCA6)GzW=WD46mVGJ z4WzzjL5mm)Y$9w7qK}|u5o4f~ zY>`CSf`fcbybD=WOWVoyete$r$SQi+&)w>H-rP5xyqB+3x;n>E*hGXXDUhU)x*q?W zC9S%QK5q4})NB*pFh(-|z+`UYr@rQ$qP!{LV%ur^(|dV^d4FBh z+xR@rBoAdUUKePyj#YL9iZR@!!H+S4k2V}#u5g|PdV;tc@B7(jP3Ye%!N0?zecv)- zVBsX>YaTXff4JULn|C(b2|k{%e_L~RHK5ig=d3L=P=L2-y|b+9IIR*MBzkT`2a#)` z&?(woG#>|^rXK3|*i}xZo->F8^X?D3-N)`o8WZ-mO(oYGt_^ndwG>-al05NYY zBa2$%y`natC-mdB`JC#`1@YCVf$Sc7Lj{jS?+RM(YYnw&dJTz@bDN1q*$uO$Bu{jO zDO|;YL%IY>$>llU8>7Ky?D${#6v>nkl9oI&(@-<6FA0FP*oa8jR@j2uSx31TASLjt z^1MSewov*CNTqn<$bT}-hSV)PW?tgzv~33~@$Ai!^v6_GpITF~kS_Q_bk3U33;iyF zPGaj4eP`n#OyFO_LktD#QRz*_=$DUO2WzX5|Mx=TaLHEwV|up3^0r5xBkJ#>r*xvYZT8fkk810Fuyd-a9zY|#Ix>M@lU z{KB_2VM}FZceP7N5P?pJYbV|xlQA6{F}Bv2swlNjy?_nu*y2({*q${mDow_Zg9y>xdr$;PWK^**g%I%@CAWP40kU$GOA^<@);*UF(vM&pnGjI z1+k}rvud}rt+~;}p0gBUST%s-|E49rr1-L@)RKNr`6a=1ol86(Lnu9CTU7fFtNY>f z!6}lqYes9-goW$w-ACt1*lfC^-v7JqE@{uIUY|SCixfS490FCRp*cD%!AT1&NL6u* z-qpMZlukpX_o@W_eLgVDaktr7Sn;&bxA}%!4|C*xDLTQIx@_?*C(nsrPLKGkIu# z(jn{0@GKR=!a=)dKJ_V%GGq!7U7imkF~i}7S1i_9M%`>%)Fcw6dv6{;-ID6uVjy-8 zBG71Bg38()dK=o7({4!Og)emTs62Ij*oA%y?pf)0+DRFa2G0nQyE)E>Lp)ywrOA2+ z9SE&Nr_0T07{GFzX1g(eyY7mlRguo)GOZFc$0dE1!HmjE4+5Fs0)O_Gd4Pra_L!$5 za8kwbk+IvU6y=~5t~G0b!G90kG0==!lb*Y%k`O$T-x6#BNF~61hiSd6UmYgul?m=9 zQw_zGI7=!}mCQ8Yv>LP91CpYblF8_|!rRGS+i${H0_p`A1Gm1Wg7|uw_^JKOFp~~!uN))`G>g&H@P!IZGbkx)9}d9zuz@@_p<_ zC>jqxQ8$W?)g+FbgKz(*$s`wzwUgnh>r}k*={y;O!Sjinty7KevbZ)w58cVK@`K=c zexV+aepC?Sy0hdbB#dp)^oDQ5(`sE_IOl!&)ksz$^6E!zbAymvw(^O zzFGjFSui!u7ArW0;ZOocw1Z{p$m~5Q$K~cXE&~jAoOSzocP$OCKjz0@DiT4gh+R;T z|2Trr0cl;8eTXiU4-7H)rM2Q|!J@k7Gj5uE+AAF+z&p{V*-i#ug>!9p2ntVkScS~6 z-Cq5^bbdvZC=1FCz7jHXwd%YIHdrp$> zwPgwTbtG&7cEA_}6P~tx#3XzwHvgWPx)iHgmJ+~t`MatPX#E{h?9Q_78NHgnkC@#~ z(fP#sZcRbF?`gg-@F230beyPw7|qk!Z!;TAM+!_i1isWvt?a(+B}B>)#of1~fFHM`bK_ z6{g-%l-^~hEIl#`4M3A^?vCHHX9K=tI`6xWiBk>mPPVST0|oC-OJ@l~Z-6$`7bhxy zN8&28MRsAWVq;9gUMU!o8kexYTv^P=20O^>QyE8t@OD}BFNt`?i6V;iu_l&Sjf*dm zZ=+n(?M#Z-iuNc=hptny;#wc|1DFFrLZZ9vTbP@p7$5N#gNZS8EDyZcxTS2aSN>3D zCPObLu1|-NLL4pm@7b!WE$>nsjXhr6Comel>662n&RY207pQ$zpj875mhT2tKB9wwj8-g z-^Ox{6lIvPJ-;0F}>qt&0JQ$(UEIOE|su(Ga`uWCEH^p9tTDqIkyL!(yfO zP9HjvpLvYSFNLS{$`W9-vJvyO-I0_X5u8upUMoy{u+9pNe(+f`scwZ2RGN6rAkFOy zI@>>=i*Q(on&Qh&t9T95V`mp-$;qn^PH>j0&sdb;LbqQ)sV(^HCn{no2aMM0+{FOy ztu|1G3aBA>q}gj0t2(}S>e;kMe1VmIW}qnfRafJXH77&bQ_-io41w7wr|OHqJDC6z zTEl8;wAA1z37hcpio+p6&5h*ld_7{+^%?rstGi31m6CM`5+VvgXVKbBPe$LCUwrgE zs*;>v3)ssQ< zoZ}M;3AUu9$JxZ>NRQf0Qmt~mUmw^HI*B&#dCxW~V1aZ~kNbqEm*0>v`Kafw28B_8 zRxf;~mPngXyL`%x458U}YE9vnqw9Vtiyiwpyl$6xgKoVGH|Ot9_q6<4@mIHBpn4)i z1Y9^$a4xF)5uBkW3}s4(FB>-qwpMYX?B;6Hl9J!n)xXJK1V2u>gPOOK4u!LvjdsiJoHg#iabh%dKh;&u+Xi-x@>u;M=UlyUyJ|ghW+AggK#meu@??8v? z^tIL;TM-ZQ;*LtPt)7>~rseE5=W!rb{=g04TZWdED;J3#NbBPIkjD3d$Jr;eFp+yU zw4z%*gl5`2qNJEziCnHWx_Ds(>_v18UBvQ1YbxC4=mvpaIh5&*o*UzG>g-SnPrGo5 z0ak>EMlq{?mWM=7<|PayYZnoy_c@aBTs*9R9(l!2{az$G)j9pyhbII+Ph!(;uZCw( z-W#bVv43?0Opcu65xYVfR3`vyZ=phm2GB+my)iP6MM>Vx6Fy?}v5{~V<8H7nqZXjb zg*d29FOYfNCn|G;{{y#YPf)qSAmBNic}gqGf?Z@i56B5!mn~6-w($O)u=fa0uLrYs zM9d*>aD%$R#O4WKsF?FXcA4K7EFW%F*1gz#(~tCQxd)d9vW&uKHZ;;uGu^$FdG@lxz#qic9n_6djAie3t@u zooOm^btMq*IO34gZ&IIBS|XJQDwAx4AoZPevH+<6^-*WUrxy-h0Hp+@vwX3itn-<| zCrNq>9-N969aJ2(Q|p2eM4W2EZ|9nS_p!l$Gg%#UsiMqsGVp%+_S8{m21xd_m|n`Y z+W{qbdc$&noR$PAV1q# zOWO*K@}#2&@-5DxopgX7Mo8+3r^1Ke;sWdZTjF8CCz|&kdLWizPUcc<*tZTiyITu- z$|0d~K+x^pqVl*&!ck>vmw@h&H0~0N^T#W?*$=& zYk`{_SM1-ZJJ5IQs7P&KbRs1cuZI!CGqC+6b&o33B;zijN$dlB6yv|Wf}l}41&0fkP?}Yd zWaj@Sn2xBTB6`N!n%tKDc{GKo>ucPr39qbsh*j3Mylh z`&`V1=S!rzZ*eDm^I|;SV=wCDK}}>S+iOd!-WJ~Av)6S5w*xCxlcsdjz|AiE^=m6c z?SJTIpLHlG1YS;PASyS%L?35MoD)cf)Xw4Gm8&sypYivz@nz0MuarD)(eVcqNW*Xm zWIA60frnO=!E7k}jerrS8W4&thgju(vNYc5#cWt0gs){r(S<));aF6gC}#_2gS55R z)h__(1?MnCsJOjE^VQ)97R7$dhT2^tL-tZ}Tpjg_MS?rlH(#3AOO)$ zM9enhfA*zaxRA1tmc^O5i+kw=#Sb<`KL3njXYI>ChNARU*lBNBAU6P#rUo~V`lSU{7ppxuj z8Ahu0V1D#*r}D~;tgtvG?^AYZy8lrtuO6eC8Ur)-uai(;H|;Jz(5aQf$Oz09;G|XOpa;T~loAI^-THNTDnh|Q3#f+2XcTaM+m6i&B zm90m#sTYzD8iM=2%@?Ev4n#kHg|j7+oE{&5JoDHR($3zia!nDjHQnc0!k{kl_?EMi#PmN)&nxbvWUUI*p z#?^qNIN}DAD(}D`XN^4$x8F>k=oBh^Cm9$w^lEDMt70NfqdS^raxS+#{S-8~TVuf? z*)BfovETT(4cK8Liq9Ye_z#mozv^q=3;ffJkrm%CCYK%4@8{z-7(}1>PLJ5ZW!?)2 z)TvoIkZZoye#7mOTap)2a1WkT%>cQBmEL&6el<<((zp+gT7i8PGYO`s;_%2Sm4>4r zQK_#3Zx@-N`lX{Bx?HJLeTl2f(9wat8;>%2r00bBWd-j%48m{a?^4CwStoG33TXj91(^iBrjcc3p< z87q$olX8OVi9Lt_msH43!Nnt^fzqTy%WXJ$>53U;Gy5$N3JAt&RRwIIB~lw0yE$OGqo&SFR6NHaQmwYji1A=&5N3!%85~RKI)4; zYo54)nla3%$Xb>L&KuK+UfWHK+s5$4L`lIZCn#B#kQr&g*2==I&B!oY(s(-=R3Pfzt(`dqVuVE3EnvjWcFcgE%u)jsdqJJ-{J-c|%l9Hqu*0?7`z2 zDUw5$c_3R`IZ7Cx4eKyV&(6u&qjAwb&)Kai$Z2*sBQYOgxF z0+o=dNI7AT!}r}!BQR$)sae;06`KdJ)6^Oed?cfvbrkr{B=4X`&(CVkg(@AChe!3C zfa?Y)ea;#yqU?^TjV!e-*Y(A2^m)LOdxN-9pQN6#n-l6T#&Tw-v(hK~jSM7I#9@tN z+8mBuL2;~mnL%lcP<_};fKkAwwv2-tr6(L0WJ`fwged46tp#ekQMt+_B-9ug;E^S|_p0*L zp!3puDW*S`CgGA^>^KB`lF6$-a!^b0)K>te5@;&aze-Ky9V9a1dvseC6aOOlfa7o) z&(I&mv2M?x#>V|jQ2taODxQvN+#x>wMI2JiYmXt9J*|zF|V`m3+8P9x@xu-qnE6*;ThIv@vC1G zd2iMc;ekJx^;8ioOh<`U#-Qu0?(?s%e&-)2l6T)3=;Ty7sa^NgD^pNJr^C-Xm7qJX z)JALDkYAf$Qjn(Q!mJMtDN#1sCMDltVXH~2&8)N!hB^EUNFfn5ke!~Hlv!4dy}QRl znKQbyJy1Re=a!-H2$K$qgiz=-YOxUPRg25Hs5iX8QbrW7o_l9?GWx%?icr|T#$s2C zqAzkrEULY!JT-L=?QM6tHe+k?WybMNm(>+D#A(Q9W^N7*p4h@iDx!H7Hx6t)=hm_{ z8UijVQ!w6bBf%1g3k}7j=?^40s@n-X2EB&8MGii-svz}3)KK~MD@73DmhxqvE;eVd z{sLte!#*a8_gb7AE5ueAh79j60}#=qnw{3X7}3f&LG2MC*=kQw0Ed~j>7KSg z;K4NaHHtGvGcP=Iu^dmHe)Vm%W;RDkk=8+L%Slw@OOvbh3HZbJkhzZpy$DkfPQ;=A zQ~{=MCr4k-hs#pw3YNw0SRKf#Bpxr--fOO?JqfL1%owRFcnlD*R6LLq zl;S9_5z9DJE^=1-N+~)y|ETkl4$;M}Z#m9WE_j==VzX2yI`Cqx)XD^eADPptnd>_1 zVeA$2agjyOfKVS3HuG1^dHklB9-%`Z`t2PA>)_kYk=GE?Tux2JwniSmk_tRa4G+FI znrB{#I0Sy9?2SjcL@+sK>c-twr1?jPDw^)TZ* zR`bHoVbNe+Kp}diN$&GD9R-(NR#h3s2b{vJtFY=O5f;Pql{O7p$1$f-N<1kKDKu@! zE3B|2)kR%l#6tf5naq^k+^$FC3=RVyqb-%LSqrLpR!M%{^u=rcUH!m}SQi$7mdBJ) zW)S?u+s%T{kYRCchz=DSMOy*ji`9wyZZJXf@0*NJ(wglWIq3%(Xdhv>S|>=7R;N68 z#S97EotaF7@aJ9rK(yY3g3uh=`AO2p^xJ#-+w^{b|DBU`$rTc{r*~pVg9zXgXp|Pl zgi?wd7D7C0NI+|^vOXZ*x8b|IGK{`%5r<7{+qQLZN>#5AIkqsOhHF#Qw1gSkgG!0B z9=_7g#1eSjqj6Q8DJCktOB3H(YFs0&t6E4unlq@-Ll!^FWs+kuF6mE)FIBd5N3f)b z_=a-Ug|j{1N@Q}%%nsSL>~-x_vlV`GqS%Rs$*-u(R4!&Jba{H3PwbHq#(r9X#Y}>; zuM$YSN2Wq-X#p0L^J&};#6|Ie3po^`|9gWAX~*R1q`Lmdu@2A+Q*yA!hE=7Tl(J#% zQq^OB)W{Ks01MFN#W{@PSC_dQVY3Z;7}gZ4nk=Y2W~CpmOh1@$PFoJ8l|4mq!MHMc z_QjQlC#v}GjgT#4MxQ>9lu(8Rufs;#O{kOG|Dd44&fb39-Dg!ckBk(`TI4x_1`dBMLD>q-tl*%G# z?n<>nY<%dH@2UDyRwE@UY8#il_*I~#rfoOznVg(%2OTPw5Ol-Y{m-0~zdmek*d~(+ zRXE*5Uqwl7OoO#EJDiRVWFtD5|1d5+nhDTnvcyHUod0my6BIjgBtX(uN(EJoL5z<0M@TzSme=Khz?8b- z+qoP>nNS@1ECP2~hs)jwnPS!OlQK(j;+JmQ=B-rwh&0`9bJ~@KxRYPX99er!Qdvo9 zpWmmJhH@4bqQ~Y5W~{KBR?nK%z086Q%D*A+cZ8P>5H&DJ&pUnhc?v)|RbkNvP6H60 zs=(ivj;FY*o*q7;V&y$0YSbGq=RZ(uJrf5q(C$cqp17&VTeT2sFi3RRVp{sQk1nLjU!8=Gz2{>5uIYu#)76;+XFxMis5ob2HgY732h(s^ z6SZWCMLv7QM$Nic1ZWj4nj6qh237-3eFJlDp;r8t$c@8)r@K<%{8+g_+(+t73Ro}_ z?m_y}g{z^a3T#yRGSBE46ljRW)-oc=Kak!PbYA-_h9|tpQ@!e~H}TN-*0T!Qn@AkZ z_nTpe17|(xp+e}S&OUw?%Iy(wr!yfLyxb6}i38c(Hx{*?j+x|Xy`SE1OUi|O;!ipw z+ktQr@#;ZbD@InwuF5gk5Lhd-;lPZ>hf!&UIx<@p_>!%PbA`T?(_T4*2osCYs78q+ zz)>UBJ-STb<#Oss{My}{+4`hIc7>maK^bGvr>d30*ItSq2FXR z*BFsq^V)6NVcHcksBRf;$73f0P=3q&+r~pk8zeKvd=TtT_9eROKB34 z!r8E~B+1@XV0PVrV+TT*pCA1P5GWJIO=-F+kSdaj2)yV4x$>3i`Rt@Jven0ZV-^@- zC(6n|rq*#kK{aHTr3bd?ac{J7`uTIJr07q5e+#=m8Qql!C&p|19ay1A>NUTaa{2!=Pj`Mbd*UC4^P`XX`C1i+;?XPGVG1)@U z>WJ#q%#ifU?+2J#JXL6FB42j**$xwZf)IFBvoO4!WI-v;zRxcE`neB*c`P|7C!Y}l zQ0FJk5_u2R5p@B`l?8vNYDiDOfofEA!?i{G3s}<;jKc_uZG)=UklXn%C9R8;qGg=U zx=*I2xs=OhU_8mL_JgJ4k7GZZG4s2d3jyjHh%oqixodiJIEPHcF#Y*=jg z(q)E&3(yDqVtLIqthSw1r!ut`lhm;veH79XSkt4g2{t%deC8gVa44w$4cP*{pqn%M za*N2Jyi_1HjR}>4tRF^pj2FLJIl(X$&*4Rtjeo}7{U~;=I~rA^gZt?~=a<_nD?P}f zGWA8=m!#cDi*UbpBS`G*tfbF}yeM_kgl{SSZtxM1#jr3To1RaBH`Jb>%uvcffF#6- zwAc|y`9G-a23EWKU!9h_^@pFOGXP4K530%ipAY3hNEtQ#@%gpg2;cLBY43r>j+-jv z{8zXa`9@X{r+H?|ukaHhkQnyK52ls9b4<4rw~91dE|OHSulRlSj2zVxnd@;T<449e z>8S?hzubI`puy0EfWVGs35c3qQCLXF$`3NDI*`EQM)`K9h&B=TjHr1;sy;b{lCo&M zpxJpB^_aX1C|F9SDc|fIKUXQzhfTC1a(#j!n1EMuXJi|yh^r1M4aug5jcZPri68dA zz>w(nA=ze0Kg;1WY{rC-%eh$5TDjVxcJw|D5AFwLiQ3O+vKp(i+U_2e%~FjUplqsoY0;^1a)I#|J!gEKNhVukJ@- z>!~zst-RGD5N_BhLV>66E@_B7DB1>vklOv4mfL*YW*wID8H&yJ|!MX@84y;A)Ny{QyhUw9~6QvIZ2j7}`i z!ompb-bqot3R$cJ`isH>iCKkble$XJXb-bwILUG?r%i)epW<2w&z>^ZfDDNWf|qZ)V$no+qQFLRexdNb_sTF%Z`W=||L^l}(IdB=!$VnB51}LUR zqpe0tof8k-WfK(%fqCH_rbDeRuwOBib7Zg<#`2l2Ok(cdRLZ#OIC0dKG=hwa+-lp# zph|F!@@Vw|2iP4GgxQ0xw8Qr(NCM^*-SPDnK=Ph(IjZQ9MtxsmcY_c&AaQvv!E4*D;eJ8s6KtV<)V4;&(X`QS{7N37u>f86&i&SAE~fVx7^re8}=3lMP38OOT-b4hgB zuaLDt-|Zsdf&V`A&k^#gk$$|kJ;6eAt!z;bEH|2B0JS_+PE=PT}J1sl(Q|%hV|FzJ#eM8 zkK`;+^clV{gpVyfGVXZ4L4m6n2YPm9?%N1pe(dDlko6iyr|^JGufI_;lSo?p8&eT~ z48N|S2^r~ao=&iD43<+~hX!4f^WO2h#2`f5unx5&s;bczZGRc?g@fI3GIggKg=)By z68KE02Z>i^NhG^5nM+)n5)jbD8wgwE1&-A&p>=w!pJe${=8k9yg{awlTC9eMx7iO( zxL_7-)7BB5kIH>;3Y9RTxw<(r#pg~ln9AB+w4p-`CoB9AW&3DYa^__1APs~D4(a!o z(4Yup@;O7``-Hj@DwY|Rr#<@=rRE9u7Tk9!(IkIB`8J9!N)-lv9oC{T{?3K&@3-gF zrL2h<`!{Xt*PWFJhfuQ0wKiV3%BzbJ7-5=XZ}E)gvga3eKLqyrfmqGTQw&#mAWr&3 z4G4gP@uO%|RH_A4rr;ZmrSJ%|(4JAHH(fl3!P| z)_LeEq4F8Pxahlzo$|)OFs!?qzoC1h+XH6xN7|BFYP)pd*XxBV)uT(UYQ`M{JU8jw zq6mMXA;8Vm>PcRa8%x0ApB-FsTCMv@eS||zB9X&T&8j`f$Wn#&T78kRV|bf-lAL40 zX4-StCPQDSoks*5{yEg|pzY3o#_XgvICKxZf>STlO(e(X-8vwJHUdy5k--HW%wJNi ziE;`yjos2>A4d)tPIPZsg^-J*P8~jgc%v>yt8p^Ecnj)McdzWQt_Yiux|xYhS|I^z z9-y}>ZZJKE<)5%3KN94-k|r)qeq_Jf+i?Y5BQ#6LZg-Tji)pGUrk4+%W+XI}B0H@I ztdDvUgkNC6n;B!}S~GERrhD8cVj)ujZ_bz~M>;T8mC9=fXb+ViZw37g7!6nj(p;~8 zTiPMQ7{N47W*rQ2I!*i}lVmI5Q+YfaJ1nZCqcEO`dN>Ao~HEk~#**@2dwj`AVd5lf?CUJoiwA^<`@a1P@HqoIvrawm3>1?@U}s zss2m@QBRIxs=h4xIiK;&tOodLw!?pt$7+_iQq4g`TBK^6HyAeEKo@MuEe2+9c6OE0 zC`u=Q{rz72G|y`oy!%uzkrU)sUQ0GKdD^ESJLY1+J$>TdyxJTTAvYq5?yW2wo5Ij- zlcFXtFQz=lTXR$Fw+h|sTZAgdjBqC*H};{<_Oa8YQPbU!ZJG`OJda8FwxKX70S_|? z(6q>6Ix?THxpt)!D}J;sTXmc*2Kad=?`G`Q$x9jt{fDdD@}zjic0| zXu`U8kJ`7DuVk@mecwN=5vzKI(GNgZ&vzDhL4=k76S}2Nd!hvk4g+n;c>j!=CEQpt zvdMz26TWBF&B3_(#Z}bN>|G`JPFS#2I+!;2`QgKLg4UYVEC_0d3JA3C%*|CUfd*mO z2U_NoCp95oDzt52b~F;<_A^dS09H$GUq_$BjPr6OQ7XI4@=3tTB45chpv1obq7NDV z|3Cx)PY5F$Ol*d%PStrK?xKx->M{dQKT5T?-q#pUY=8UpgmN;ivb$QI>VUrne>R4s zh*F)LD!pU;o*hk+8xlwFhSUt%o(hX}_fY6umMZv8gyCbRh<@ag$!$>f8M+w^;yTUT zUonwBdXE^D<};lGc}~v#DcWBbeH|sdjrcQq>0|tRx0Y|Pa4FD0@*ue`jQ2e2*e zbN^QYqAQlEDjXc-zoNv(wE5j!LGM*XOR^?KxDxV-HOUZR5 zC(SZ+6e^Ln7m4Qn+3WV_PAd@=qm`m&}0wS(oID|>w15G-b6l#3)^p0nZ1m*P95ER zUs9VHrKBFJUYs3LunlCZa=e}IYn?%tEr4)7oBjv^nbhQV=z}^@2b^mGRkw^fv6Z5y zpn^YdW=3DxzBg&XWEek$aK}zouVH_R{h7BykewP)^5FSuggJGWuf2}ytF;-HfE}bA zM<9FMC=A5J$#psp4xMFQ3E;k8iLUKT=yjcnttB!^ft)tZ`FwOh(vqd5b73SYoI^liS&D^C3W)_5?KE<8@5r(NC(RtF2W=_7j- zPN$z&jX^pbyU~Ii?ga5qQ#LrVPe#~^Z~^HkF@!re?Rs#ZrnK*fN2Ixc6mA$v;n=G< zX;wAhIZU8*Sf7v#}j!sWXaWfTPu6x#Oz_%|HtYaVZDW%FuSf~r9S$%Dw zNwn)0tUc`Bk({OW`3OF4R2wiqvo_o>rjrKdzq`Q=;9?yAu{>CAFVE4a2{qt+bZnJn z5{a(KkY*BUY%|M_xju*3L;PbOq<%;hSXgBtjdR9}q;WY`j;F38zo=u&kxFPqLPFhn zzOKh$VQWb4r%dX$-y)dZvf4cR2hegH(k97KK3_V{nC&aTv6%K^YmJ41CXPfOs5$k6 zPh}1*x0hvHqOYJ6wiVEUl~nPg0jC7h{6|8)C7lGVb=3>Z?mCp4VkTu@ePS~Ka5V-c zJjzBw2&G~&h2U=0d2$Ev=dOj2o-ucBx!UNjF2kJ1_M|97*-oL}i{hirt^B@sou!kM z)c@;6j5R4oTVLD8Htr$UWA*G2xXT0zSs@ntV4seO%AW%(PoY@dZk+15tm`P?XF-)j ztj*h;G#@g)g0}iD@>qZ@n&*7j2wWEIYFdNaO1OemBO7y|;Q+^5b7`Y6zsN3llepx@ z=ST@i`WHk?SyWnEC{v4sgr{28ykJD3(%aW=d_ciTDd za>|nyBriT+Dm4NE5G_edDN^LZE3NF+YjV0C>Lun&gqiEuVDleD7IA~Jm2^aVH>d6q z@64VEZC2q2xF)tnMzKXtK=(+@tdod27|5EDnZsUEmx9|c_spw*F~TK)9-SnSpj-*su(~1MD_C&Bdp9g;;E!jj7-ohAPSr z#+&&7z?)8zk#W3cfoLAC5Jd$+fK}lzmP|Y@y_gL>!zZK)L2J#wDfECy3W=bHXL=vC z9D+MnIV>HwFF=!7aR9i}hkmWz_(dUKj&GjQKw!vzI<~R6`?v#r8dv6_=ev_6q9ce?v zHu(sM9!jXIv%~mVx6nWGX(EgdngTl#;UgS#tEU>#=GbQdxhmW!-=lSW1uMJ@qM^|n zf7(VvtBNW2QJO|yIZpJYv(%DJR2j+?iR8$XRkmtltV0Zpoe~|LE-u)r8D!ur)a$H_ zhHByU!lvO_^63y_AwVsJz*+PS7H_LHU6%)Q7?MHFUg?%p4Sa9J`u6v{|CW8umpWsU zo{teis4JD`nT0$ac-G)mHh3$Wv3SRsxP9*?r<$E03t#kNi|)DSrTm0>jXo`Q zGU*m`=$@93T4%S&yH$RqXJrj;1?T=Z4j9?;z0^!3Nq8w-^Ag-Avnc)pYt05lu;!s& zdC}d9PA=LKgaM@Bq7&KqEeFVg0YPuaVUxRCALPqI1G=%4nIo14vvO9IrEspBZ?O9c zG_5a2gkS?4`iH6spw(6XU~lpSzCyuSY)d6gRid0)Xxnj;=Nlz`~FdgZVhQ!rT>Zv-K z9dGZ3WOE^dOqIWNOk(V8cM)nKNl!QpkDHF9!c=L=HCFN28|8zg@KYMdC`6liJD@xY zgdCi6@=^4i&|JGgUtK2V_JAyzsBxL&HYo1@)35Oq=pR$vRQskIsi~yb@7w=mP(LNS zL5XRrcJCbd0d3Pn)mFPHqWz#+R%C!+B6QdP%J1Etlot|);|Ev~LYGfh;oBdg95B9~ zJQ~Ew^08<6E_`=rrXyWyBQQ%`d4BsVM{dw8u=zV+A*UIxQ;F*y9Rn#uu1#sK!t$TZ zY`k%%*NLOLr}U>X75C|$A%eygebDkQak7Z!mZ;D2MFxqZnU7Qq`-1Un6h4rx&>J{x zwhf9ik}Z#%)l?((_NEOc-Y<$dYQzT$ZY{}H9DMqdJt!jB>Q{uIL7AYmDMuO@_^Y6*#?>U~}bt4X0-q&ib~xiw7z;|%CvkCenE zS`Wd!52g-*c)@=vj*@(=c|pZgeJ_two_uc5Wjw0~>H8lnR?W~mxOP!0m6%KrqLF+0 zW=HGJX}?lZ+2<{t6_Ou$vc}iJUgi@*wEK!}G=q)@6DyEU0!{4%ljdG_T314M)1=YR zjH2@YM(L6ocm~Rhqu2#sBGyoMM5amGe0ULkk!YdI+dI5rjYT_iWM(bK^KY*Sny1UY zVHF*D+I~YV>!-u*hjq{89;-wHCJBd@Xf zvK|-xi-3$QO;MyL467LXplp%vog(Rqjlyi*rCEH$SQu{l8#P6vl5cLxs%B((L6GGR z?H}sM-d1B9?qpm$tQCp+oeqWmvc7rLhq{`HjrrfF+Pq4)vV>6N+V%l6K;tPujT$gr z=~+Qqw=q&ty3_>``4`{BIdtXlrI>e&@EvaNENZL5XO0_DlB%Xx3tB-6w%k?4(tH|~o?*zo?4Ag&F zfCTNRKQd#X%>0HIyiay8QzgU&77w)e@9*$tEnr@lx+M@5Ty%sBZ{#vJ1nC3Bs)c)Z z7GTzSpYS}&(W``c=kXSJ;hC#KuX!#T}Wvi-lUXo2uBJps?$g5Q&y12q_<|W`s`o|V+Gl= z_c41$^d&?spxi)nA^cin)K?rPGi@u(?e-9t@E0!053nC!xpQV2SAur*HG|$BPS|53 zBI=4YA3hZZ#g}_fG117a21ffvKoIGCP1`U@o!mdLmo!BGulHYs!GD@hDM}Ns{Se~3 z?$)%kC*-3n2U%bEk+_Gc@vk(|muA@J%R;}=u$<(ULU`}^8kcXpRV0YZg#1bnF91x3 z7o52g^qBkhsRF`KV z7H*)*pIO9^v*$u`?`DyC^*pr=j#Bzimj9Lv4Sk`iOU{7kl_$-^h(5XuA$L%g8St#~!p#mY;>&mGo7xF%;y}+#h14iI&ljHc>uSzUP(Id-UxX+ErH~ z&3B~s=E11t@8b2>tAw(f1fdt@Jg%dZskBlvgJi^73`9idEJPD3ae@n$rgcat=g74p zf~}3pVJ&-VgXw;nv)SZRp*hLuRyi+B?>@oAJI)G+n@O^I4B>B_X$C*o;NH9F`nvoE zA-o_Aj1!K%^N~tWzCpf6x zamN|BKxWfeFo&0$qy^afvIz@pV>nf-l)DyX{ZKps9Dz9V8nWmKi{f8(6ks4RmV-je9d~7mkGhWx8{a zZV2Z{WgdkuUOKB6+^x$;%pw0_(eN+NlzjQZ?KBt7Q|d{LKZ@v)@8R*a&3Are&cIr_ zJ(p5zgCew5he`6-sPT9<`)&uSuEPDUAPN1Zg)Qv1^8X~{_}I#4#h;S&u+MRXzH(qM zBXvI4fzJd7qrI| z^F_A*tK=cuDL)QET>Tq>W`@1}kK3$gqd!EDqTFB}4cqpZnW~x*lVIA{UFVF9XpEqX zmB)+!?V98N@bM>9;=N|;YMX6lski#Bx1qrj0aHgeOrPe?6u(%Hiw38Tnwa!VtO)qI zYf{I3Ye<=zGP5_utv7n#8GPCp+uv>~P$mmb;yk9ggZW-F_Bl2_5h9-Cks1z#fm=JD zJERxd22XYlgs+rwA%yztnOEJ?nH}zN!|{HCp{V=r!IH4oKMuU-s$>h*%bx`WXrQe( z7LQZ1^07LR;VWr?%15q1D4g+2TZ!G!w8}*+>9Jy+pw3HOkaULg8&1xk5?mN30DhqC zvBg}iwm9Zm+?Wu`GaiDwFW7!CWCUN0EM1e_Y%f!2jK8l;;Jd$xAdHv~__w@|JpTC) z59tu}W6K;5ju*_~jj};QotnV~mz`(UL ztw?*e&+n+l!-5(jCS0C((?M|HybTA7l%v3iyc%->SDFbcj?OIa$zwKgyp$OPNP!j2 zT(BF^;nLpkd)&)JRX@=qAR2m8k39ht`}kf+DDz6YZExNB5_p|(DcSM6UMRd495+y! z{i_zkERgIpYsRKZ3w3gDsO>FxL=@$a>`BX-I&yEX)^zDvUD%;#goN^meQu!cp`z}E zC9kXrdmlCB__1Jjn0R=f^E(kzb5)}kG(R-=415}?+#bpn%1R;P;aOn5iUkhF7XP_? zcGp(UOU^Ekg-%Ctovt6{XFRO+gOgDr6P))N9(gv;Bjh+wzf^5V>8JL#TswRA04U|E z5;VGnuXMfIEN625ngY?eUPE_>@A}v@$sB=naty}e>K`9$GO5=vl>A9d4Fm4>3mOjv zfTQ9eIRcxD<1Ddf)4ZNy(QKqfrHHmfQoyVtFxe?V-EkV8C`$-9Q4 z!rjjht<1F{Q!c%e+nxs|aik&-0N(*lAkCcT3`3VzdPAEei8u({m9oKb@QhK>hbIl( zPhpb)weWen$ep~PWp1t`?#yF3zbE=z_5BZ3Wz+%@1?gwfj$Y2#m*P`VnUx((|AT|R zfp9y@I2eO-Gu=U9bbCeE$2Huc`4D)NC$qEw_{>+imi*5f0T;mG+1Up{&( zuy{iX#*!+rO?g{?E%7;gxCSm}eSn)#YYr&XtRQ0O%6lAY`)IEYy0aSV)o;L{`AP3i zqvLC@6o!Fen|hFstodR@83lMPChWbni%`Zihj0E54BjZMYKf>Z`L_+F(u^0A~{ z-%zWrPBZMCg=>Z>GW0!m=Y;7GuFN_-58lvZaUD-a88V zuadOPXiLForO?%ckpjOIQS=UiVasv+SEQZ;Cv(ee*RePE9^)i9+38pZfBO93fT0%5 z$B3fTfN^D(^#akyC)LvNMx5hc72?~_NYZgSq?cajSJ0d|(gtNRYt}OZ&*$hMw%$2C zm%8$sAoFpPBg`FL;y$WKncPoKSoXtK>`Xe-iE4>4d|@qg;M1#OKj$-W#g{HGwTs-E zr3M@J<*nJ8bVJvu$GVSbb+~4I8q4W#!|boU%qu_;%V}_!jmf1EW&cJ$UD>5SnqwJSBZYExJ^;-b%0paX;1#FZH(s(?~P~*c>?%nCY&>I ze^uQsSF%$_gdIExa;{$uWcEUVq_Z2h$avLQQIk_!QSd=E5P>xB_+a$v$w37%Rq#{T z_+RvY7AA_AYbaAl3T}1glT<$lD1%Xkq^}$&z4?1x*DG!Mk+i>Fb)WSzey@|T%T?KV zaY^K5rno}DCN=-%uiDArc2d6f8zu zw;y*(tvO6KV4H_9<-R0JuD|~x;OI%L$L^gozT7^-=ZE09vj62ZRu9dd6`+ZJlIcL7 zq%iqIq?^t&akE;&@3p)M$d7RUaUk{Q+A>(AIDPy@$gwB#?y)~u@7RtMZ|6`$`1H|ppwxLX}F}S1@hn}7bdKs)ssDa>X`HRs?+<0wL7!1p`)4>9`6^1xSo>S-=CEJC3qUMs^vP-FPh_ZS97cd9rPvws+O53K2A5)FJ zJu=aCstp2by9Ku@44+*BxF8yot+!v`A8M$wh)GQ9LSS?p8HPZhdF6!4zv`dQxV-XG z44drIL7d)3n|T5rRd}Ec4}H8PgiR)cl=IBxh&RV>BBNxvSen@L%pU-JV$#w(8)H zc(*1l)f__?10Aax*B0`ND1V>AxX0~QPgLIl!28vp$3edBfrHKsctYGdhAJB~UF8^o z0CzD;sn!KcxjAMtV)T~Ufx%NU4TT{Cl+=SjVVz#I69n4oW$7m-ZvtY-r&)s`tEej0 z!}pF+1lub8C?mSct7es`)QT6LoYOBLRtPnm`1Yx;tpQ?Eqg!++cs8mzUUpY6A)|wv z>}n)Rq?L2!k`C2zQ=2dXsm(QjmAEzp0Ov4Hng;%=UX#_V{*WdS*o_y7JLIHY>x$soo zffwCDw&l6guQKjRp6l<9N?dKKo0-E3kRQA1NSB?)*7LtbP zc!Z_x7x8!kb*n2j@TjU9vgBMH@zi3-zkM^DQ*md$lE;AO zYRhh8kCfBJ069R$ze_;v2$F<9WimEsVdz>>T8p;|%RHV08&ARxlDZE+DDc(Bcf7C{ zuO|5y9tYBlJO?Sh_as*%9yJpA2}N2HqLVNh807{`Rs8;rh7YT9+8c?eB+7TllOQ9v z$DT@2-;=18Wzz_#)2b9+M(gIFt*$%DNpHPy&P4eZ;@gK?EaKtb*iPLn>%dSu-`>Oy z!wwyq`%bltkD@<&MCTod_>;>zk&Kna*>k|lb|JQ4f$f3&p$V{>UUBFgpdQAkyH;00 z58lL6SW^k_Tk#EIW0j=~n}xd%$p39$fDLFr4`g0^Bn0>NGAN;2mCl8s_z(^*R=}+8 z8N+VVG;bLWhkd4S;Zl0~`J=JEe3njj}ez8joLT z!mSNljDWr0;Y-@}2ilh00o<8EuFQ(lwnY=rpbclk^t5H2@3w=Rix}8_lj#9>kwjko`c9n4g9yKJreymVW1Gq>uv1^2#LbKOgU?0jX-sMMr%gyXW*sL7vEEpG6-2JzHm6ZEDTd?X3a$W1u&cv3^ z+0IDxR`HtiZi@nNl)pIoH{P3@Ef6RpW9lIqlcP!sQ-{jVUA6p1;=4XZQ|ex5gxs^i zPCy!91!!L7qnI{CwYehzw+3Q~6`3Oujr21rtWpG9jD#P>vTGwEZgO5JfGwzNHRSc< zy1a`yPjurC)!xR_gbNv|pq64>=bBF*+U7Qw0FTnUzUoCJQQq@qo4yR|Ibk5{==dJ) z9;irZ78F7(f!D+4r=x%}v=R#?#s8@A!jUn~Jtf1`81)Paxt=1OL68D|;bOSDd}eS$ z4yYl69qba6tN_+*Q2NFkCt98?ahdFHui)#3of3gq&gpxYPqm5RuLo(8N0e?#h1+)` ziQn@GO(IHfAbXW ztA&Cajosf#HUr~`39tQgq*&Js4V@w$3@xNIkL`0GYc#;K;?;2*q%!DQ9?331xH}|j zkTJF&TgW87M~>4D*cX9nfqtF`H%{^SLaJ8!LxTKJ=g@mk5r)BeFT!4= zLd|~MYo#M_&*_>q`VQBJ7RF6LxuV|{EbO*($#P}Q378LnCo zq>T$hmqEpQg2?2#l+QUvz;Q(iVn5Qc@hoQx<$0SLS&b-m|XyJ{K)Tb$^=1X)1 z+g`u4c)NqO7eQ8&F}RKB27u|}gUo`Nx((oe&m|!zbq`Q}Cq2Z)cB2JFpitV-Fxypw z$7rVIlc(4+6kBGR*1!@qfjy^5(}0wuYQwo@Z~`#6-mKXlf|3W|S*g~R#BZrv(2`k$ z&5lB@{cAtD)$mjxq!Y`@=gATiWQ9~Bk9P9ib$i|flBhqZVy-%kn8D~&sIhT@!2(}T zL|?o*@@3qa8IiJrX<54EQHPcNdrT(@@rbz;ndvnqSJHWUb*SR zYioO5;m#@jr4xg88b{mNZS19!q(RKGj))o>pvDWZC`wqcq)k7ZsT9`O`V==YTbk0O zH5^T&?mhtqilHbdN{J?Texjxr(W=gP;q)k7#OxX=Wp zoUa$z(}ia`6l$C23-F2}d8#d>b`KI^VO#&v!*?7|X=TBFY=UsW_r^Ba1Sr4-P6;AM z!#6(4FSuACAKMr4L#(%-DH|E!s*c-CM0TNagFp$zehti2Onm83gh-4!(8fRgQNpx{ zRpcqQ;i*+rGl5H3cRCo=3UO>eF@KAIHY;p&YEu_>sU;kP9W?u6=|?e_$eF+=csOQ@ ztHi1f%dz&ABCz*meR#bd;{prJ<3w>5zhc2g(guW6eKyMbT6z^RxM?!A8gS;*&Ikyh zeuYVKEF~WEg7>TCd4)9i$T>==yzJbm=c*cLjlrG9iQLc^r;8DfJJp3}H57v{eb5`y7LXV*Ei(s;E5&{p_q2IWantPX(=h@{ zOztFX#3!Q|S;AM~D1TZt2fw{dG=|G}fyK$iQ+o4AjX0m+K7#+tL5(#|&=!c|=r=lz zuyL27-f$vvsr8Aj(1d8}u*mUFZ3{6*;_HbB<*Yzbmgl-mi|M@?)hU zSWmp9Ku|Ko&Ge$C5R*jT$cavG`iXmP3pXQvWrw6IynijzPq3UWipQQSC9#2k;aJAp zEz)OU+n~?wAGGU0fRc?dxPMRR{#l(Yn2E6egLx1_d#MvGFS;=ng=17$1QQ{y7m8ys z?F>1N{+)Re@UOwdqaO{jOH=M~lx#d68VH2FM)qq4IwOv2W%TH#b^548BYbl2Q~PqezY`%~3cy^*m8 z*|6$m#DOT_kaDco#gv)?-709LFY(qq^(ba(X7V8bTrOOor1)L(gjvn)=839Z!d1x- z^f_}c%}yaS7YFFwW{JjpU{xB6W`(^qN8|K;wBMcj-613e_C&-)3yd&*Yl45FtT()X*dYmvSC7i3Lq3I9%HQfx(QbtkKc|lbNIZ zVnJ#4W(L2qfliC89Fu}qfX`@Pe?ENw=f9ihH@EGu$76b1>mxGqt|Tj@b0|0Y+6sg4 z51yKL&oxnQVm9jmF*Du5`B>@+A&=r<)0S2KNf5jq0tm0X@c);3E+hKh)01Zs82g~v zl6r90WfY*qT}L{X?63^^0~?)Ee1tT-i%eKK+2lY^@pxt4*xh!oR_`h#>KRN|ok6q? z(?twUeNrKq2iueA=I{ad+P22nM1})X+O(J$zS77AHrvTELSNdVnH4}&B&Ifkch8j7 z^s7bc2S9TCSu+^z|FVdF1O#?qs$7Gr)A}j5oK;obO$I1~EQGpy@%Uk#^vPKt&EX=! zblw)qep;2)~cU> z2VyDDLXv40Qju2%K1!|TN0|k8IZQMMT^zQ8+8WPb207I_H48J}YF3?IyLC2)H%o@H zC$o5zsTkHZP128r4RSmjTZ5k@R^p-{_D;&$$cp93>Cc+BOH-=H*L(BE-=LN<+_}<$ zNW#HgP|?vbQwJR%ZiC0WT(x0J-#)qR?dJCfqiheL>f35zHR{vG1>d(@(U&;aKA^c3 zPScI4=Dj*}8|R7Yh%Jzs`94^x34Y%V^)!T^I~$-dnWh};Y7z5HO|PrI%fEAQSW!4B z0_gZrR+d<%xCE5w!ur^Vo@rG~`}IZ8oT-uqBG_ zrvG}xZw_bHLi%?)OvF?*zIg@Gle0N_&h!P7=F1VjVbyCW=eGJw3ddgDWf`7JTi~}=KzzVk13c#^~ zn@`R7r`ptK)If}B5+j&@zK$UV7MRN#BR7(lY%Pki?zZSjCDog=L^S{Qh`uXZDRb91 z+1;UJy+C{DQq+$0Ke2kAL#jo9^+MnbG7|gwbn!MnLp)Ui@HF4m?TiJih`9lBojZan z>^U6DB+Q>vNUFxx&7BW_{V`4W8lXZ{9}EIu>DyJ%Zzf+=%fh&S&1;kvQTgL{-bfnIvWzHzNBmH*|kCZ zH_(N65e6)w#4MH=9DOKKk*Y}CFKrQD&-L@)-$anu#u?h1T<3>`K!+BOy)wWWP7C6+ zZ{>@0*5+7lX1lbfO4&_Wb*u@hZ={de*nb%ry$v_G>)UxcDc_PL1HK)0~sb&S14bNrL)RV zJ>`ZN4`|N?R0q*mj?Tj2Kf{O@21F$jPaKl8)sq6M?*LmO_p}-XC$nu}fFJhgswV!6 z=SGFK^Hg7uAQJqo=N{ars-RW^mfFSqrJ&5(n1cd;Ybn|qsx_UDD3Hz&V@WKBT{Qn| z^5^gBk$!V&(4wUinCqrh#E{_cY1i$%v5J3NP@#*jo{=HxQnp!ny`}NPE_aa^;u1Lfo_|TEEhK{z~1C2P*oC(++T9!6I zQ?VwX=q5Upi>QG+_4}3AhOT`Ypaz;_^XNyFcp|m_d847Ppw1&0xw;S~@+qkJN)u1;97zkmTn&Ni5 zh&h?o3^S?s_;SQ;gV&YO^8&Pj05HXN1o}3H=d2(XVG+f~+Xhx>m~tm&i~ylmEaD&G zUnS-(fooPrEM0_s*~fwVDLidS%rmk1kF3DrEt_ja$!Nka(Q8i5h3G093b!L^z0_xg zf9@I*xno~jGn$e%%h9aIk%1i!DYal`|umd=4H6c#Yj8D3vBDZxr`Tbz537iUl&a^!*4Aig06U%tzHHRbrF_}yAx|-Yz%%z zD+r<*%5eDPRE&TV{M9JhSSs+sXzw;v)W4FWvG-gO*yM5#EGOj5U=o zOZ-8@JB~zKClQ!`;J+pXA%Oarl< zxrhIn-!Yooc*!|11GT-{2tpr~RULt|bs)48{zINZtoSWQ`a5AqYf~0$^!QXy4ukW+ z3{_(;88_VA7+2m-%+PZ0qZzZ6J#&5?H#jRi_%uCKq%~NMw_2cE^b@qoptRWT5Cpow zFmN!qU|KGeoTB*BH|fFL@l`v~>zhGV;@-H&lQHN`DK_k15+t~`RgNRxr~r_Uy<8VvVYmJab5BP5NkI)PGioF$J>m7 zjF1+r<*<(R_`-f?@RK=NH@ZyX@owLm?}N*mdz8Iytv~Xo)B}|DMiR-(fW+Xft^evd z;{nkHBL(Xp;P*yyXtk@Ov?Hi;Mu#B%XA-HMlHEVru97E1t5f>b4H!NVnpxW9eA>qQ z>R@EYGSDouLF(!day_s}`i(#WED}^kDk{P_3WYcvHwzLW<)Q-FTy?z5rqSgoa@|#h zp(#opNPG6KW>JQ5XScit;EjxO+PV}rCs;2_Pc+OTG_}iI*flot?=A&~F{6?MXzEQ> z3hDvM(jnHUrl#Sh_Yb;4)49%H1pnOpq;JVUL4*tdW}*ZG4EJ8C`GsK<{-de(o}dGL znrP#x)Qbj8H2{PB>7^~A;^BMrOiY$T(%3d<%h|1E3%Kw}q$ltP*|BTo-kAQo_-P|_=|4b%FJsSd6g*9onYn1& zBcA@lQ>0HIr_W3c56VnTEy5mbyIp3UPv#^wYJ)-H?!c8>aId(N^X+uP_P57uyMmFPz>M&{bTGJR zr%bd09z(U_k;Gexbfvv_fr1ODSFYfGI6!4MuzIx^0~ctT zSZ8l{QAbB-E!8FJWKk*(Nmz+*jrd-jO{hdY9myL{svx3bWd*ggtx3#WAJ?Klpypi? z^(`^q6@|J|!X98v&c-xNoI^<4o3wW zlMT)$EmdZYRAO@72g-bnKZi2G1W2|%kbn7KQ_Xa5mkg9|*iXy;O!@8RI{UxIYbiUt zd`Asw8@&{pv&W0GQK%u3^!=I)Gf0{QhPRy$YOKNugUA48d>i~oJziL-88a;1 zNTN}Sw-WkgE^Z6ZgaZffI57!Mniz6Fxatj-_etLYUfRpEQ1n%q@D1(3!Sg2evwdMIuoQC4Mk?TAkh4a7HNl1KPn zU1N{Tb%W9y^Ll2^5#U?=67}2XhJ~=@8%31i1xd*(xqwkF5`b-ctSuzZ|6q{1l@n=# zlGG8+>H?Q-syvayQm~&|fS{7kqZ0(&{Mj{buTf;k8vsrEwwl)oZwIYVt%&wsF@cL2LO2gwiRjTU8>;mTrQal<3Vg3gGc>l`p>Pj0y$mz{ zh(!9`O8(opdI@JVCUhFd%ey=Dt8?8b?Sn3YZ4uO}AaUfbGL+zD4%q1vMg*ysijuA(P|vUTSp)jo^)S z5mEj5>&6LBp@;Go91{*#=(M{PVQypkA0VN$O+FTbmU<{(4NnV!50V1sTJrCy{6{8- zzz3mY_m5-%q*i7WCsJ4nEzVW%mrq$ES|FV=(gSQFoHM2vol!$uexZchHuq()+gD1Q zQlRb!lwyEik+L8J7urbxB6`i>)Qp(vEPxT9TLH=2c>G)eSJ7Osgt?g0%9;}UvCBn$NGA1LVi*KA^#5ErClEgfTu@{N`PR8Ev;qW-bncr z-f8kxyIA@OT6M4KVo%7owT99@w$C)AkX~UJYsq-$9Lp;vus9cZri_Y6N6|RaA;7lN z8Ay5kMlZB3)xDYXPQG7T9vyiCkUqs;OH#=K7r3_OQ+eFe9?BPjnZQ> zw~e5H6_ShpigY z!f%8?P0H4uqJ*;ypzz~q{r;?)PPkr@eSa%^0P5! zh{fTNnbpbcDQM!^;=K%F1*Hn5hLjTAaDm9!Cn=IQkq*wo6-9?>B}m$H=O3e({{vQ5 zmnV0X3#d*sR|^X)xr-8Gbw&-fa=woq1}Yn&l9`C9$S3GPC93@ zh_^@2FOBS<)Qzwx!#o4j*=%0y>MJK8A1gD`E(lVd8sKfHlu7<32Lr5ow%3%tObl+M zGOA`mk}S`WEnwDoVK4vUF7)?vXrskCAZ!ON(0l?)sodTz@My_`8%z@AU~K-I;-PKd z0$`9h{JCXNF|o^(uj31V7dhZ6S3}0lFL|&_B_zTKT%#_-qn-6V;3yAOU9e}=g^B6Y zLX2%;Dd7ahf#k0@YBe8FC_uaFY(5eEzu#2a-)|QwVizE%U-*}X!?8*v2c6>)$0>CS zwB0dnZ$)b=wHlWoG%|$DcH!!W{*J^dZESE!jtYn{XMoP|;>Au94 zS*P$8QM;#N#O5ZowyIY~qwuK3TUA>f4Z~K^=pTf|1E%!LFZ_d6OA&DAsiQ<-rHV~q zDZNoo@-uO%}V8 z{W_Q?%Lf z9eH+)x+aP)=sU1_WnYY!3=ZamOSBt`N8_QKt?U@T@=ykj8&otj&XlASbqG>$oYn*U zE?3Q-ga!$T43GAb7wR8%lc4)UmSk)SB60&hdRC*`o!@m?u;kv2N6?Hv7c1ToeBUVF z-`8S$)O~6^g{GtP=KyQQa*)8p3>JXDlV_MNxT^7f%ScLC$mznT!bvjX%BiZ%n@_(? z3cUz=Mv#->Ti6sAdI6)j*S9mO|ez>V+;=_AH38ZJAKUH#(^m5!cG)&~urh?f$q*2Y+XPe}9av969H;aJ_N3K(AO zl3*w?wb&-*p_;3VWB}Wvivmo2F~rX%UbnIa-9>{>0t-J=&7?vi%=xousy}SpkRZ8!WZ1D~$i7TwZpo+c(a|Z^^KF zMRzduuLlO%&I%XWc`LroP*%`ZaF@B7bD-lCTlpWI))A(EiA`XPl}?+FT1!<^OV$Qm)2BJ_4tBzcyrgh$KZ8;XboaKp&vw1fv{y#AeaQ_1v$jpzc`+qz8 zcuzo^x9bM|v{4@9cdEO-yr9jCThXy zGkzxG-MV!zK(RDO$8?s0Ur6Iz6#2CQ#RYC{RT=Y_qF4;-nm9UEscDqhi6*LO5kmei z6^Xzxg}9tm+d2OZbKU1dTVd#=)8P+M-GG+M$M$$;8Di$%Jr?rudJb}&#+f5bxJUI< zc!I-gedRWop}PCC5&ryO2mJ4(dVp@eGo{2Y60lB5b4U~nw?DOwiBu|qyHBaN=? zjEGb{3B;74T*;_B3z3afLlONdeF@-f^PJwlpwGbQ{0=)=RF(^pGcTBFe6fyIp{K4E zzB)xcEBba>r|c~#J=AO5g5J*d({&!|{7;7RL24qETz+*71%lM`>$MDYG-BeBTlaH> zhH2#rJI%GJtY2nMm+H**Xvfw{WRue&z5*rQ78ES#EaBo$X0K_`~iP|V!JCHsWPy+ywD<}A4JWUIi-PX>t54^K zhoU~bVZfYc>wb+6YB3JWkblxwg`HX_S)hC&%#z2J4i-G6z4;kzaupCSj-80_#~6e& zA;#jS7Xdf8?CegZ)uql%C;=;M+t+v90k%Jt3GH5airr1LJ60}_SKm<8gi7}1$E^0l zw-z_RqS8Y@N(LvnMDVXzNRl9nxQ_CJ1gXE}A`14Yrl~^GSe6F$+?Ne-j`54f?Fi&E z77!rQZ?h-GB{_`P?6q(L`L`nAK@W*+L}J!3s7hKC=|YM8IPGmwJgABZ09iH8!!*Qz z0*?9_L&v4!00^$=oAK(SRNu^{J|ByfzWdsW^#aVIEOO(a^Y5v8D zL51S*D=8IY*zTitjP|5pEDWP%X#dYWlX+caAVe8#rm(V!k?L5O=a)|4C^4YyaIlW{ zX9L}u#BKrzNOflW_}FDl2*3{mTaVQ2t{dLYe?0^D8t*j8V&7$mPwMtplM$c?yyp1E?08W?{7)n zHO1#;#q$LKYbxD4OYT_-%2y#_?eOWsygS3Ze^&ijV_@$h0fJ$#7EE@J?10uk%52bm z90W<}%4T2Y3@N(3y^1R!&mUE4OC-&6L2)E#r!m4CGKv=gY8x-W`VF2o5bA(bkIzv~ z3N_;=_OfwNk#4vO&ID#g6JF#()w4hIc6Z=1Nikr#8-mf|$za(){QB`PgJ*4mEMGCW* z4_tKVc%s{Wjd@csx1kL4gUF}j@SvqtYgbbtaQ{Zyz007Bsn)K&n?)hQ>D2 zfRYEx@zV2T)1|L|xtJ6U0lFl*pyCJg(LBVdIa?$g`7g6DX;4e*C=aW-%{qZr#pT#g%Y{CubF(8hx3V_A^3JU++t) zzplgSO9GmvlE31(+s4DN(K59JBraaQ46S*xaTO z1C{|PIbayjG=E*tG^^Xyax%9;mA0aq^Gjiuv(0113deNSC9T?^KCk$+(y6%xsiVezd+;s1p@Z0IBw-qHNmXv)e6vQElVVMzmbSuH7pVssCEWt5 zxyu5FIm>wjJ+aQDC`vlS)v?C#lzeW;Hd``*?G;H|^C+nYsh}*~7;b#A?+62hvpJpj zhJ{&$siy6*CNV`><`SH*5fR)xg8z|D{N`A(A1s?l2pi$gKSsUef<~Q5GkF496^)gv z8<<1=ebgk{8q9B!_cMH7ZNNoL4VMbtmW?CtPEaj^MgtaBgPKZAuU z?aBkGdM;xHJh1{ecxKD*=5T(yZLTdcrJOV{dGV-Y@|pc)(CoefO$ri6)unLeMWAP% zyl)JkJjnMpdjrFWZ#|rNd6M3LK9e>I7Y#beu6H1roN{`IdmYDOyRBqQKvhyW@`yz4 z)-uSKD`V1NAeaLkQ?*&08iz>(;LyY<;Hwg%3F<$y5+zrU9JWrMlA%Zv?J);mpWQPg zWtszS^751KoTm2vxP1&0jvJ>-!)lQV{UZOHJdVfDrH?IjsBKYwudE5SRhIO)oJyPu za06o`2T(y%`YC*#GAQCUl!{$aB)H#6pohrdOymzR>eJSJxLX`BInjZAAdkJP=WYN;dEVAADMD7d_I_mcvgUb)CWu7TJ8wJ?yT)e;3>&((s;l7LkupjK4lo3SQSrl^oA z7Uog9duV$$xW1QZ z6JbS7JGT{V0l7{eZ%j1w(M5`q+wm|OTeXdbkJHZ;HJCacyu zY(b_@r?~rW)mK3iDiBk)%6Gl^lId#%gormgq^d6>CHm&ocyd7`>uGi8QI0F~(p@1} zV};;YqOIwk&mV~?Ik zsl$6`j#kMlIMuY;uwC!Qxx-rp;)F5POC4#fF^7zT!8LsWZ$4Mb2iPr~7N{Rkfi~`L z$r3C`SWWd7H}`1F{)!8MD)1{3Di5!ztIQ;Ki}gW6tGAxa>%HD8tdkm+(j|IF6w&V> ztOo=`gn?rwN4b+met>Hl%t|;M#i`!HSLQM~x+q=idHEqC-I@Cj_eZ?cOHnKMsbjMk zJmc`_C8xP9-4~Km=2=3gl$50vz`(qdMcWf=cS{O(u&LX*K(+X*lJeMJ#hIR%EE9%L{BJrxi8T9raN^K5E2F0#++7O;owB9(1(^XF9wuo-#=K>qcHQ%=@ z4+K0mnOS;~h#&+AygjdKx22^5|7SmKt9s;F8hcd?1nuG~MX6xMwMmvl_aVkB61m`l zNay&trJ8gL1&u0a=B+nRfbg{|#i>ajd8J3rUP?UVMv67p+scY$2s-mxvyT6or*zD^ zE-oGbZbi!rg{x>$f^j9|_-W#|XBvRw-}BPY9Ob{hvuwKa3_X`hEjIn1d_6N8xosq~ zJ-s3G2bN`zYAqsKg7?hse|mmLX=mda4A#adS<|sT=$8V!f)z*i5B)LAMy8g-MGE` zmx7#KmpT;}EB;KgmLRVbjY(+$mYdhgHQt*JnC{4W^x_Ne5F+LKY;%<=prVqei$y0x znTqZSpIQqCUWj%gBHDToIfr2b5B$IpC=-njGW^dnmi)e?@OwFnUxnI4{nxlsr)KtR zsDMt@J|D$RC@-315D;udVr})LI1Ij`w`OkUlVSvk| zKt^0{s@$3k2veo;L61{SA-37scd3@3Y?L2G!P0ohr^9<*QLRxlJR%zmf|twLm%Oqr@3tp#EWVCK^=(+7bVI zI{maV1o%ps>6nONiUE488;pfydXeT*84m7Fn4#{$ItimcWipavC%*~cIP{0)gZGmU zzHj%U5^T-siD?bSXr=;cxP1TYK1a04XE|5aaLY)^xoFa@4n1N`fx!qZ&b!AA2o=lF zGF}Rh4RAVX39L_V_PY2tN<3n{)u_@3(S-k*KVVh7?jCK-R2MyUY&XJ1aMng6m95tI zhaF(CuAtp($vH640cBTMk0qG5Ml7U^zScL$84KY1ND<^$Vi(Gv!^UaCq}zhy_`4*m zucmw*dH3fTIwRyMD5cD5ZjKB{wz7s`eZ2ar4-luiDXn7B)qJ9iNN1Grkc;f%oPsYw z8>>iyATH8QXUI+rnvJEiIG65{eO+S0f{6 zlK`pL+b%21d{L8<<@SNv4&Z90>JLlSc-%c8v^mrH^z;U zR()~JqoBA2(c%EH)Bp3z`H&=6%loRsF;}>Hu)Cg5zC;ccGphFJa2A->So zlaG{-G0L4lxV^c5!UQtSDt`Bl?);e=hwA6}$Qs|98I>aE5<7D|>B?BEHbn{Z2%+lG zkyIhf?c{)Qse}CxE`i}=Px=R`;5TORXZ6R+UV_Wtm#0C6CSS$qpNAut#^OiDySbAjmu`LtDz2vX9Scz#JM~DX`ull_d82 zsSG9toBWWHH=p5*v|@BQI;7=+RDtU=x0wws;iILI!K+kTWc%w(|BP|Ays%9ulmM5B zkYc|>vV2;PiIx^{KBuqd24;cd5{N517#~I|8uAmJo6@fT`sbH#Kf_nQ*!$Mq)aBzL zK`#(@Hs^l~wz#VhEr0mbYXwl1*!vE`_E^c`j_y)CDO(haH~2Ix5(k(OHB-31>++!= zC%kY>#D*bt?8o5Zl*0s|H7wBa(HkZM(&N0pAJs8uW(2OMo9pE>!2H=q+xl}Z09j81^ypxm%tY8BS%%Y#!_?(nNR$4K3*B92 z-z(9J<(58%OWpk3(NO5gz4hQ1YlM{N=pDzg*g~zTVF;Yj>w)VZzMh@#JJs zlrXdnnMl>J`~kx^*|iWzsXR?$=C?i`jD(s3ZdL7f6Hz#WY@POagLXbf0yTYwX4)>| zP+b#UL1hNAwT}{l#{-xfx2NxN$4>ns%oZL;k|< zJ+d3q(+xnD@>{FLLzXibH}Ka^E2hgE`rY)g`!$>NY_`M3WRs4tFy(8=T3q3K&0x3s zdvePQq4Tc`TcGNzZREA3QHgGSCKW%m-%G+OH-kRNWC;sbwGmqnj}m$4RnDYVyM#yr zvXrpfx0POp)468t|1|P}H~4Xg99g@(ZE2WmbC_pbP3InyJ_5g&7hp=6PSz9VPFQh2cz*BYHG=+#c;Ckz|rfQ_;;t@y`-Ok$_s|Oi zyyIuye|VjBSrMi9U3dgf7%?8ro0VRI8%j_jgGVL{p&(lCVIhzK{-F4H1p{ZN5I^1X zfRK%*U|8=&FzVrTgEho#B=y2C@33__k+YO(=MQY<;Pc zWQ5E3iEDo9$f=#eRRJ>@rg{Pi0$v}2X8+jDeU=N{hpXi}yjSW*L7lz|!SkN(Ii&us zCSF*z2`K9ZmEu`Ap=yf&=3EmKgMGs`a+l)5Sd-)AF4nr7Mbzh{zahcoY45Mz(eu8U zF{Xptw}9IulyooGY?{)a*U>Gaw|MR4L#sYy16)XoZevMp+b!v2jK(@=3|&iM3>bZk z>l9DSP_PyRZ&0xglej52>*+GA2&1U_iH}H|F+DMZirMhT|K=|D6}Z-Sl==^dgqJzH1_9+Nc{c|qu$rVPrl*Zt5Gyz(2>Qb~YU zfZfJb#mK@_Zh=p3W>8x!vu)`t4d?((Z3#qnQZ8n>Q+J2H|BrE@I3C&Zx7cTRmzvNP zr`qPrtg+31ZKS3pxGU;MR6_P$9IA*L4}9R$eM=G(O+Op!I@H4QUo|KZ<`~3A7*vL> zwx=7Bgn_xerf1#-Gbt^BIcQU(x8hJv-D8kM08t+rDTx(i&aT%Fme(xq7>xcn@4C}Tde*!#(;k8tAl0Sr3Bg@?W+ zM~MoAcHI_g$Fiv`P}D;3G3xSjt(Or@IOTumZDuS!VN*1$3%Lqtjij)@W&Z)Z_-UUE zx|v%um;Am*E{AI22^uLxW8}F*P_B#B#yf;T2%ZRp{jG@GO8XaiF?f%#j{g{b6|Hlg z+G&q zY8jUWb*cA??mQvdt+?pl%kJt@kRy#2*^>`QZk5--Q^|BLZwoQz)cPTZTZs%%DiIfwYPQ4hRf`nMx?1dLSuQxD00YM(2LC4IkFtIaUv^)xjOwcr876S z(pdC~9AsGK0*m2P4r^0eL2Hd6i68hLU98E5Kye=AuOo^CxKYYgeon({9tLU^P5lTofTslLctJ)%x7k~XZ?*iLFV~Kk? zQ&t3g*l$;C`~?qwMMmt@-!QVn9@vyum$)6&?VFJX&%SMa*uRm8E> z)`a@!U6%R1c9fKIcU$pQ?ZsL>oIY;?neKC@&$(iWHXqyR?x80!K~WFQ-HExmEE%F` z+T9f>t%Y<;fpln0n^tCyYc<-t1@g4aZuMavuBHVqCzr=TT!P+%?7(L0k|JohAX?WZ zY-O^z_u#79$bScHbByY8`LOV5xYCUI)kBMdhqEkj1vm_Zk8ueqbSZUJ++ZR$pTeZ_ zh2@5!mLO&`(osG7%s+__}brG$>EIIpFuY z;^2!vMXfU8^<5k4=}VNH6=f|3p_$@OUZZ%+foeoHuP*0_8pnz*H^(KAz6!lzl0>19 z{^cLX0k*-wb731nEVpAa$&_W$=QRhVB90y{xs}!Qxd6wD36+bo^vB7R8beqZCR#5(t z`7fcjn}tlUPZd{1bAzM-*P3No-_WGD2I?!kVq%n>jb(oP{mI9c489srweGt%99}n% zfQ`|a+{@gBuF9RAznZ?dGR3D=_Mt?M15s*l~iO6GIOc0D9zi?rMTM=xl%QeV`Vg?1?I1=04xE z=cdms3*m%8Jt0H^{2puoOrnr1KNKT!i}zWfHs7q5_KkEnH0|zx6|=Ulxlp_85B4#=@rv{_ z=8D{7&@8lha8D#MoTj$z*`v|c239@2&R{sUcDPY6xrBYG4>z)uP@Ux(wo)J8@hw^& z!_3O}FsgJ-r{zn9{hV-Nhll8V3#pWR=ExI=`>lr|Q@{(%taZJ!4H~xuO@U8OhE@M2 zLLEr{pii5td!ai1!ML%Y!bMXYHlY$O)^hGx)R zeNd7_-wb;uWQe1*As#Qw_5WUYr{^MAkLs!p$)p#8ZFrcm9Lj8Uup7`g6Xp zda4ZdseL5IerSM(q=#m*1wR(YEwhKK;fq7pvsa};k!+idQx4)}=^@FPNlk9C0wq{$CO%K=SG6;b^u3F<@y_tR`B8fbR&n(z8RwGOKjFEXTA8KXDR?Sf>#>_wSmj(N zp0u#Rng|DmSXj&K5>>3$A@$Y6Jn z<=TEZA8X0#rVD=V2sRQF$9msf>M|>(6OQrynt}+Xt$l~(Cm*S z>{3BRdo6kWWgcA;&bN{d0XD4mYCLU`iFkO!?gxxQvP(mLaO zj(@4Vi`GFy7)?>GsS~1Gl|*s4y4;>g2Z2WQteC%J$E30V^UiDeo|sfQCAe(NL}7Ci;kQ6bZVxgDiQ=HC!^k6xk&9lld(Eq9CCSK! zULqMQslF?HK#m@%A*UMi^weku(6>Ch>+#r_0jh(9b-pLTTaX_o(FGuK*fD*|<}j-& z@R)8^=T$==9FzHM(n<2gWR|(_7ao8VwX&3k40KzDTWj8bLk6551wVwK#|!L?P#3l7_ge;rlvt zL-Cy0wuhu%Xf{Yf{EQ>juU^Pqq#bjwwuBD!v0%_5vf9z7R94st=nI4<8N*b5MB9K- zC&Xg)mPJwWmZEU&E0QiJADzJmPv0C~MY}O*Z0uFbfo*q%JOPj`|8|p+-cBSMn8WRL zls4cP=qoHxwQ)yPE4fRp-5+LC2^CddMLp~)U zSieZfEw5%wIB?%dhSf(K zi&J96^d}fIi_60T)i;zNN(u(BXC0WvhP^tOMrixJfW&g{*sk3=wW@OrjXdWrWBYJ) zE?81jH@+Vx3x3RPofxDuR-mk)vfrM_?cldB1F<2^?Nf)@^m4et^QG~+-B@}1EnN${ zYVo4oYu>+gjQr}`<{gu^Ya7kBp8T9t7oIy9(g@v$H)FYT*Pkr``3}T zQRf}tVNAKTAeG9P@$i2;4_1xXMk_#8$2AN@nx@VW<>=!R!cl6(vje33QXl0XubcOF zZ0U|JohAcrgnTM4OQKf>q-Ct1yC;B3BtAbKpRo4#oLkK-fjjRH3Zlre5ExWO7a4Ih?UDfa7uE%gqD~#IyIa#Oxuj(++ z-!nJ`(v`ZxR2jDfop1z8;0%0)sVW5n%100ZydGszGCvw|p1Ecg{2+#l&eT>86qUGA za9HceDpQMm_y+jc{*La}m>Rlw9pu&N@I1fA6@56l`JCRUdzOZ{Vpy=j{<(cL&&Rahj))P*3Xcrj{w zwsPigffcQNynK5fHK%cokD$X}H{HR3Q(pJX!2Eg)g zc3_#|k>Xa?dz{YNEW-ZOZTc-i32~=DiIcA+D93v%n1}4%9;h|#Q@}`(RDZXh=`ND_ z#sHk(|Dekh-Z=#_tq%ATNVyl7y+^4Ap6>$|rO`baq|Wfqlrd3{nYk9o*EGE+w~2y^ z;67MzgK=Z(YS6xC#*u`x9*wcF&TUekT91HofpfC>bI3J+DP&6k_8GxZ5h6o(t}&wT zxsQGf2KD%80}88n?NYd$n7;2B?td^295X7BR+bp=i}JzK-Y8GQlhj`WZX-3-Nf*ar z_rixt1O87BX(obX`IFr1ATNX_Gm(Q8ex42jZBCP3{!IB->lDpX?ajz$Fki7VOy3TH zn`!F%tk15!5kGSw3la6Kb+mN%3LpjL!$~wy1DKI@-})KxXsg%o;(;Zxi3d80$)0UBqWtoT3oHx;!p7(T@bL=!du#{6}Nd$f4Fs zRGd!oDHz~I>LvO)LUPCGq;1O#gxEvVBc_bQvhPQwyRjQN6TGLWd!*4SVD3eltuSK= zwri7J3}F?e)+&cMNH2-x_zhD$d%A@K;MG2!5vToM=PQ!4ZI7b;?s2#7rYc;=IlfVi z4$n|l`93hX7MwRJrl;*Xq)alJp_vE?6fO>4D;0<}w$C7YM43{WkTjWnEjz*mPBoKo zINrI#;`b@**>NTD5y2=H(+hEHIdB#eJW{OjOxD?Wx{zG+JD54MhLwwYCM!Y9(OwNY zolfzQ{Kc5Xt5$)}W4v-N=&b#sT;{VA0*D!D#j=CO-;kFdPqNI5nq8;|He%X9DfgFu zyGp88-IcHdspSdC7q>b2Waqa=Y2m~Ae?wjswdfx}-fa6y(o+22vY29WOA1sEH$849 z!`1*t9CRVJ3LQh+>koz<0byLaY^3DxhPb&8H~N}P#$4|u(Ias8<1srkyLH|PQ^@9- zaqr68q>R)P-t`ByK{^oLX`uk&$n)!Ry4CBLzy!)&Q_>s|B9KSFhh;Sdy* ztGR1lKrycq(58l-`CPaHQ)j@TBT#@0Ys9WwSXSJyqsmEA5!4f(FsNuPgp9YqTokUK zNXv{kS7+3ls9PnYpa3S_YA{mZoYII1)uA^|-%kSE8}8F*1zQd72@ouWm{gLv12eS} zpThpfXAwl756cCAoc3DX0kTw(3_@OswUfBhmHbn?3WMFfF=njB(!qa!!lZ`10kc7U z86!baiqxy|wULn7!Ge%M=Jp{5i_Q!0ckDZchg*09&xHSzz*EBMs?n!U!gltr1vHCa ztIV)5c~l5k-?5})9jxg#UFO?dzEe# zXw{eXm_YA|lyajJkBaoP$p~TMHju?@eYH09-A8{Tt=75bcpz=${1i9FEn|UAW%EgE z;#zt|E>qVTm>mhni?=w^0BoDh;Q*cQY{N;ftikA z;A?}c;;b8K@HXzwJ?#&b>8^4b>H_co7q*jMg5I0uc)=~{mj|zD1;9)&sgtJ;Ajj$5 zAc(+LVB=wwFQW;au}@W}Fqgm6Dnyo{%o916)QLzM=`z+b*t2`<^hDgpY{UsNFSzfl z=Sp4Os}LS}Kk%a;3R8(PDHCm4wN>0Q7yC|(ZFpN=m!k&Fs$%(!mAcopRgTm?nqsJW z^Oi87Ryw^_>{Pex8FTDlyiAS~w459(qk_D*=Q?(Dk(Y;>%Uai070Zp>5vf+nKWLmLO`%4e_HujOQ6S<7% zz!0@Y=5D~lkT<)kX0o&Na7t=&&lx18VO0fWw*2%TyeTl}2+drq9R=YkOODAu_v?zj z?U0}pcP0-@3IF)|0O>mZa(<5OZxJ0LT!$)W=Br`QM=G|h)Bc!uMB#6IQfQ6>G%Z}g zgKp9oG`a7AXkl{9a}NX(N1e6xkg)%Ha+(g9Z~oD3Zp!^@gVtFh%3iQmU|?MM=%Eaa zJa^2?F*asH7~7!F+9#)b|ThgAeN~523)Gnf)caX+vG~gbYP{EiaUTh z%A3#)iex&4lTq69k+Llx(x$WE|AWk);&P#_c7~Q(n1!V!k(Z}h8E|?p1P%|@B?aIP zHS6UB9fW6DXHu@;3x2^N5on&yv*O?$&&Yw*f^ekg?g2N;EA?5&j8E0GrV~brfmgPv z#lW`8AfR!$d=h&N?Zw$xMdR2@mX2Tn#JD|F zhZW!aXCth2Ohu)v=*@l83M8=-%BKhUzDWJvC-G#FN!dkcSNSOFbKqNKyJFRsfE}v9 zxRGW4r(ksWwRZqR_H(x9I0r`BHIKw8_I9(_05l$Yv-t-sCle52YUlQQVpcErY-7Bi zS{=L&3ix+YK#HVZo{b4HAbz}c8JeKUgA+=re|I1CMyX0OXT0t4M27ca=k;>W5iX2D zAQ+in+Vq7(ff9}7zqg!cvw{yW1yx@@=J6l^M(e+>B?b>YA&z?%OxIm96 z_O>i^K!ony%XMzf*M`G4CGhf9<(ZoED}mO=P-;Jextd1CkH{iqGdcbnk;SZ7PIjkE zujDC=q?JrjiOj&vl7tLG^;g6WWubHGDqPgAou8XR5y|7<)<++}Ivb=DHeK)?xgKhn zGu0}ybZ(&#SjM6Tk%CoY)GP# zI&HqNOV^8X3$~IPJf=(la6^-Hm{orY6>?&#$p-jOoA|ju__oN!Y0QxB0MFw5JR{7` zqSlIvW~bzu=#5EuljP2AH0{FN3qt+_lTD@6 z?IukYAk_x^z-Aw+kfzU2gW+-u>aVmb5GvmI^ehlrwaSqGH6+~DGtWthI|Q_;dK;50 zq{s6G&b^8BX4S`@Bx|jlTcvueIjhz!*PrRB(zXT$H+PA|}Pk z3=B1UFDnH;>XVZ<-KQ`IZK#Ks{ZRVt9{L6^c{Zqro}^`rLDc;5jP7wDHemqObW?6| z^6?UJwRD9&38N1~LiMOjM_Aft1s}j0#fK?7^1b+b5H<))@1CB~VqqGV_8b4nZDt-y_jLmVFyNvI|30HuLT^=0hl>EfW2|Gf|&3!mzLF`L7|KYWuqUY%46 z$p4N`dC z8UAZ-l~hmuf4+(v34cbWErrkXRMF#&@tT$yhgz)#T*fg!+ZW=7ZI6R`HkzL0ZBJL3 zUMmWeF%FHvW!P+gfUx}3w)qW~%@N#U<{e6|Cs|Hr9a{+RY>^dgbe-swir=p?WwFsd zAE=_E_S6gZ{Sta-SOm?Dx* z7J!+yl`U`P6*X8<^0ajJ?fllHy*kpDE^bA`8}O(5Z-2^Id7$1tshBX&wY-%@FAIMC zsXU%~nKX_Q^H#dlH4k9?(nhHAs$W@Jl?BjV$@q&O;2V(a*MS0im{z%7iuD$|2|@e^ zXYAHdt)jeS%syOaq4xkt#xy1j4=fHX6z&>jXpbT_VU6}fcyY5 z>Tia_if#_V5A^D<$Dz4bXvz^jU01D$dK|UygwBZoeB(?pR?UF9s)-*yx}__0z{^6B zocqrVxVrj)h54Zu`H)5SUWly4p-;&~_%=UAZc1bYez^Q(R-L8Y0xALWh767&v12tr4gLOu@^iwhdPI=z{zPd00T;X+15S(TmkUp)l9EC{=>GSqB9jgtLFy(vORp zzPv&FN~$wOa8Ycc=tzWSL;+(~)DNjKMMD97PjL+yIRTMyQG0G9?kk7?e3J~YD?V%3 z;;uwt2eq-DCY$(=2;N=oJ%OVCaketbi;t5sQ=pUF4nJZvw^q%&Kjd?{Ax@VGa^}Bq zfIm(v@>>~OU&}PDfwz$tQ62V85;Eao9hA(_SLv1Q+9By-+GEg?@B@~TIHd&L2A&sI52e>(F4qT zr;bTpq5!SMloS-F0a&AE=%R|_Sc@ON%g1TQVemN(h>kROJoO>jcJ4D@Y=JxQZLK(k z2yv{6juujegz?~$(7~;o0Jz-EwM8*szb1r{HEEn`qjO)0SQ11i5mdB_x&aZ$_;U? zyQrw4zEvfh(s-EJ)(T;njg6weEkm28?%QG3(QT~6s2;}#xfyNx2n(VI0n*K%q4coo z#vv?vV((yL!w7Zz;!BPiorr}@16GFkNvZDC(SN*}@^mTdd_UF;N2TJQXM=}@VW@-> z>0cS~%ZQY|oerd;&D2jcGl%$n({x4UcYDsZL(aTt$q=ly<%q=z%`T;TY&3aQ*suk9 zhe<*s6p#7;61a|e+u6{n<5K=r;a;VG&$+GB)zWG100G!$4r=c6=VOC9FEfApaqsa1BDjeyvW}E_43!I#>2d5i={amaGT!4Vf_2x9Zla1u69!Se z+=iiv??6mmj3Eoskr-|64fL&hJ3cpk_CO=Ja&1GWw(NoBrRczvJX`DKt6kk?mnC0A zN+4Vmx{&GRb;PzldvYl+%fw`R1&<)FY8Qi8QG!3I~%D9>ED zM`>pz!+OMvY1fI%WY3b6_KyKmHejN!D(nu!Ou)3D%r>DY^5E~Y+9XMV_L}YKV)X@( z`tG@<+5w{KT9l7ntMZ=K0}37woxz*r7Q|bq%U;qN|5TDAJ`q4Qab0&nT~|!jFDDi#UPUl*LuLFTVtNjke%3$vy ztsk1JyFtVmi>v{d%S|E|?oPWpiLhTqW6s)$5H95Xi=TctTH9A#7k zq1HEFL>`IQZ02~f2fkLA!5|iCnO9~Ju~)dxQV5=CeRn{OY4XwJ@nEJvcZ6n0os+Qa zLV??8R!dY)!6J)Vus%_W5~F32UP+0N_zSLIVN@)@e6}Uoh=2)Hs%<+e@tJfL^IOp^ zHUb9~1Gz{%C)+`n@bUOcm#l*+g^D*QQc2TtCA3Ru<3)z=-AKA{H}O+B_ zpZkDk`~a1)`gG~^DZ*`psN=-|$wS43t&Q`}I_e*4v)0AX?TfhjTrN=EIbW#M)DAH6 zX-BabUn<9~rh8+cZ7QTJNpQ-J^dmh_hsgh-N^vS78z24Pbtx9VuivLRzA)pO@m+@n zsQ7KS#O%}kjKnS2$%Ia;2C{u-fStkUlkDJehQ)hfUaOUQVmf^DC_UVW0SB*RR-NbkLO)`h-_2gmSm^DB=a)B%B!%kOe7jyRk-B?7y`iZ9@V*y?xAFa{3ySU0 zadOj%#aRdN94-5upnOflbUd?#=}#LE$p_sJ?Y6}(33;jYpLv3so;{jb9z+Q0>}Yr_ zFuW9v7VB!_@652}M~E=H+N7>-tRE1F=iVw{^+K7?RHmBM=*a9WXNU;^;2!qbX>#ZsvJ#RwO!2~i1&teBx*+x*4Hp*@-TSdn?IqH5w8YvSm3yM z1Xfa90tgo;wT0I7D9FAjU8JgaT1&N-#{p02Aw?<3=C@!kP#<|~R9lR2+w;_V%!uOk zuhw16?=J8V5Z^KIHd9t>7T=*F1;)X656G^)*@h9}A%Fl|S9J|QAq$@W1D4QWBfU@e z8OomQL0_2lp&obwd}qhAk2dn3=cQyrR}bIq!PzM~ zP~^y+iT0}SQBZKv%95(h_4>#`li7rG*y|;dI3GD1g_*q9P(8mR1ydwBorL#WLU^VD z$g;B*RNMA1yW&l>1z&X!L$rSxnlA&y)wdN^MJH=6MQS08p)+(pvYl@laT#|qKW>jr zIS_8m%2mMgc^lvrX^LoGeJ;YCms^P=)podK!aQZ+B`w`UcjT#M~V z`#Oho$;jo1IR3wY0)_o-NjU5lF1ST-Ddw0>gO}WS>KTC-l;*$UQ=X4)Q5*xL0VC0nsC zbcaj@X*m?;PLjS1)jda?a?2%==W<>8_^^?UA-|w)7H*!kw})I{24kS{oXCuh6hR{y z*Q%HuAYUX5~$q3Gzn$I+ZX1@ zy$D+}ey@gqa+YiM6jGL6bYz}2X=g<2$iC57mjJry%7d4QX7&QlO_dl2N}8v_o5&qD z=xCr85|j0*Zk3iEDWW;T;NY2?gHA&Wj^E^g>jF&0Px}ASPTKUiQZ8dq+%f}{WxC)0 zkleDmG0c=b+K;FsbQqw1F&_QsH9S_`j=;a5NQundf2uw1QhqUS++fr*qqkZ|1QBUBh&v;iC^MXZZ;j*WgZVot}itlQyN_v&z zL<*YtcdjeNtxR7j(U|OJstvK#j71)Hu5c$>E=0rA`e=oyNe{0w(Ouy!XOzTz#Et?& zit*zj1>kfqf|=@;woA=zJ4RI}D*9Po>~!qA1bnxU*ZUI(s?04gJ)37!sdq9`wrp!> zc0Blm9BB-^%t&Vcwf@1tXt{O)rYDDYs3RdChgmVc;2b!irA9 z%ee`*dK)5#>d|#06GO>1t##j|7XOieSik-3!LEmS+|M0{OS$5X+v7}&SyZUnWT;4m zjV}jwLwiCyuTFCxKVP6)C_$@LO|?m?Hs7iFW~J?G=q7$Tsm{|#XoKdV!&va`>vTAztoXN}`I36BJwK&_?`*%F%vEO5^G07HbJj#lY z`-$=A>|PFy)Mu#PX4H=suom}#qFbU{)-#XTiCP&6s=WJdaPUv|Ze`9HBYSW%xz}|tOL4RdLzJ_d{V3m5C zpqjV>IcQX#y0*dRsOTwFrLq&g#S6bRvu2m5)ctk&;Vn@MHd$h-&P+g9tvwCU(WpQL2)~~CxdXaMh=7T5$ zFZ6L*ybta&<@LU3BP^)DfBT0ryhl(@b+il23Ve4Uw-lE8fUlT0$kJv7BEU6&QX+SC zS=0j|p*Met$`= zZoJQ~0`jul0vH0xB2YDkBxsd8xI@H^awY^e`1G-`f`F z9K+y3r629c1$QG{C1Zy53FE=J?wUK5=Gui8w14Z2ii1Eogd&eg1IO+jmrAs!sM+}fXc{(?KnBrC}N!~N#`}j-wk`a<#Z~~hubaAeByf+_#e%-OP2 z>*V+>+wZ(S_!iU*Nq^)fsqpaeaOZ>iN(HWMtKX=^NP&7J=Od#Ov_5vH#3F|Cm&s5i zNSP_lk}$DGYg{u9$Hj^~elb(l&|AxcNTD;Bkd7H8khp;_Twm~<6FQ)AIfJ9zpAfTy zHiyk6b>1(=JWANo^-uU*ZL&Sn2-@%O8`0$+>?U(Bcfs>}r;~z7q18UgFEJlar+#;M z0M~c(>D1Ix-*gYhXZm{&HptxO1J>r^Uq(y=nYhroJTRv{3Lt7?k}n6jC{P(d)D`8a zR~GIgzh)({AM(vGKX-cHqjT2+dAf=)`?SfLZy&J`Ye0U_BTjR(L;|jxl<5J zP2@6k$~@pvRZS4rvv5JS^nH3Qt8ceNQ7Riee)$*+30!InTftz4r2rt$AlxDryZmS_%p1IJoq-sevDaup9B=8E0heCgw2i-ZX`Rn_ zT&y6gElA^%$o+$oswi8Fb4sVC;Ps(}3u7JMV-=DvIWb8V<|pR|fMwSO|6{GZh2nwI z6zp|phCa4cq5t&Tr9_};zm!g$<6f$!$)IN~89XDBXLiUd>+OoBz1Ouq!!Dd#mRyr zQh%Pa$p2Dsh7-*$GIsu8Y5!@x|zoXSQdJ}&FO1_l&ha%;{OJ}d!5N#)t zbM3+IL$vO#X@7Ie4Ji|d_v8F<@ZAPcJ|N79vmjPheaxK&HcYw7j98Ny>c^k*DlJou z%|#t)yr`;6e&w-`_!z4TH)m)g44Wa2_i2v8cMh?yLG9L%L zQ=MVQN-~neOt{5uy8Fr_>qK#;9*$(`r*Wj8*=MkMD{S!6N?{u0TW$pR& z_s*vfr&q{QLEo`G05R{iO}|CQq0=)Iu;sZXnL+3unE&Z$si6^M(M)d zK?L8{YmQalrrvJoK1z;{Jv0O0C2q_mOPdsA?aCRPtv@qJ04;P!A;U$XqsQ`B!&rSH zDR)fMmEvZT(YlaGJ}8)8N)LKGw7g!1Tb)3Ql+7VVz)I}^w2FGT3Mk&NUjD-%fqi3F zjZc+3(Km$qDt0TPk(0209oS1hX%#%}wt2Q{&`*j=-vPl-5m95I2j<%&s_^j1Xm}*v z(U-KMIU>J90?e9agYr_Lub?K#d=o30RX0h2z!J@a6GT7*yU# z^xJMus68ozbrwb7`ydQnR#qQbpVNJ;aJ{`YR&U)9)Dcg+oG+uId%|*qkYqYiMIpbA z^R`2L`=T4`bQdLi3?>WHl zSLGD{ZKw=xR5@MvH*PMLxz!F%!vV#f0xVos5ZkX!eAal^o@cHZc%4Ht9sij$Y|)PY z_qw)^VQ|3_S&cG-b8_Ra%rsoY=cY*LWdK1bjnLU^#6JQ!Y+ zhMJ;gpjk9lrPl?AaVyG!m_59n>$?loxe$stt`=E$c8W^b{?l?W5||x%1(O)K36NB%`(2Pri#e)S(@li>QUuYt6PqYeCu) z&(>_RCk4I*tA>+gWN~R!HVniA_@Mngw%D@)%UP@$)Kd^_ks-KN#Iq;ev*QsfI`Bu6 z-xKgHb_hbbJsTgr|5r5a!;VuBI&MOm9UrmE%eiIjRzIEx)@lF6=uJUM@%x|8yiiw& zz;joOk7t!{xb_3!xvAD(EkS@VIL^0WEuMYJFu(GVkn&tavuL)TsO+#~Q^{GD zeXPyGVyR>B9Dlh~mhrt%*)Eg#{Oe`vp7I4Rs1ZN5atxI4{?kJ(i2+XKtrjK<>q3gH z>J1+r04*k`r|yR_!0o)4ZWk{S0FTR3Th|i<${IwO{Q*wz!|0cD!ki zJ~zX|NYXi7zR|R5vsFIva;`x9A;ldXeyfFvB%pE z+$5*p+rJAGA``Fu%%4FdUN0_#tFk0IlKC?pdLwS~O;L$pnRA znaa{$$PVB#cxeZJCoVJ9oAR$_$#UeSgPy~(ritNif6$;hF*v@&Sp5Hv+v=i(D#fQ2 z!t{fbn2c|PresW3c5{Gl>ZNsqj*wwE!LnUxo*Qrd{F~@dv0bA;cjSRfM2gyo_i5fU z1x!2{`G_K87kPTh&AwIbB!#ss(pjuq%kC5T-UWW{Gm{E`pun`9=-rUok#5s;%0gyT zWVWm5pY%mBXp$dVeqG%?&!&_jcrG}eSZ-4v*NPt_YKw&*os=s~kNg4*0>}IA4`uH{ zv8y2pv}TGuwyF<`x$fH*_Wg63R4m8i%mWuIR$HYKj1^meV%Pcs7eOyWrv1X+nEF;I z;r09xb>0u8pT#W!Ucj&NDDYrnf@n3KDV(r&SVX?g(1;i3_|8 z&?Ry;L!l<$hVyyp#CIFEoELzH{$Q!1Dnm2&`{&SbvvR~J*u~#C1iObzU^V4nEC!Qx zf3pgl)u?8KwY;WtaR#AY8CzIT_taK&&BMKP`EquPM*fs@7$le`KHNYTMW}Ia#WLTI z$iX*WIpdK5k|u?Y!2$@uN@v6sZmGdX^KCZ7`U)cb|8l*st7LQvdaOI+B}_*_EJ1d1D%g@ zne{k7EWSz!dmafXBD|5k_mbl7!%W*v_M_O+BU7?&jkN$ zl)(X;`W_CCSO%6O52o&xmBe>0T0~GAFaOEs55HAaKzNfu2{$tZs17I+NY)Hafh5rK#j4FilftJ~&m z1+A)w@z0r8-r{&W3Hp)5#5#Ko3oC42P3l+U?27U*=udzp_Z;}s2wiTa5KZ0ckEU$f zg(u_1*V5}y>}-*Jfjw*F^-k}3~9pI-%fd4d#4`P8l9ggc+Gw~WWIZ6 z9hMPfpVS>G_`R!SE1{gdJ+@%hr{|KX63b0q^tL&NZLdO!Pz+AJy@0Rqf7w05?xscX zg!vHVz$_3+DmU?J%BSW=&~vlWVl0?(iJ*r$GOFr}lIynV=702Vk*RCU?F|Opg8Q`CcCsg{dwNnnlgU5y%NLaEtp(HZ!p7B+qU+u8GGwQ+-e12l_ z$L^Kw(9x#pO7|F92UfMk^+_)rG(qgg`Xcn>e@? zF2vCEfXj~qQ+7^`XH@MFz=P9A%q13jF}qFFGZLQ zyB_+UO3>I9G={JtI*H`h6- znfZgp6u7A<6wW3eCs63y7l>wM9;38j`;U@|3ly)~%nB3Q1V*VORrPv8v$`j`aDOBh z7bmKhO$8J`t|6W2;_G~cay8wYb!hZE<*0@#eZpUS`br6|$_~=W#qMSpo)MlRXCSeY zMB*`+6$ImZ$`_ia%F;OQI^Hcob9Ul@*5MiZoZg_nSH@n~*N=ct%}RN9fm z88twxM2nHoeILcgs8fp{7Ko1>+^J)Y?ARoH9ORrHZ1j}SJ(0xoK1irUQqe1CHt4+= z!B+;2{{K3VmwNG@TOO9Kk-4hy4nuqx-TWHwArtN=fm6B(3hnDZNb%-x>xh@T8prkj z@BBOBlXl%vp888fS- z#q%I=hl;12{vm&^$F$SWm)JHrN$h*imj;ydXCVf75GdycWB+9sEQKTrRFuM7|fAlP|a#C%QUFc&IE`pemetJ-IsmVH0 zW0|{juW`p|Sf@rA%FOh6N%;LGmM9RRo;jON{JIQP3^yChKMBs3G@5oc?RdBs{ z-rP=U4Dz1bloJRKC^K5efFcu{{(pUGhU*`8hby@rf~}O9MF%Pf-fz`|j-4z$!ypX= zi(MfYFd!rkp+0e;sM8K>{^aI~UXj>)lJP`M1&Om!pgeq-P;Tihf4N6sWrLflj@Yan z!cg^~mB7@jR0q}+WT&r%elq&iVvDQmPt%;^-VW-k`DrcqU6*PhFAs zj0m|k=E&0vq;LlyJ=Hp1*y<@fNHVx!6Uk8^LO(rGud?WAu(Ev7yL1GMOeq z^MAFtm{Fr%fcDY(yhuEn^OO4a#valky>?>1G$rPI~JsW+ZBuV2B|OQPZicPxkfoAxOCk^;)<@y zKjJk%wTjnuJc=niRlzBpl6fZ+4_UpoSKizCw1QkcdY8ZkYp+?@y4shMpkZ>PeRt@G*z$*5FW+v zScMFYOECZmpa6={m^rKE3z$)b4T^PBZTB()yvvCi{MRuEo!LNWl zMRbwfjN^a_*aeg5FFth~?4Eu}U(%Y^^k0oS9nC=bWmfyv@`b&>-^Yda1lYfI!)V2wwXBTX#$yP5wK||n z9+9sCTSJHL3N3jG8vBGUM)bpRel=Bi@6q^A>Uel8Z+S$tmJ(>*e;UUhxhto(Fdf^M zIJlcAqireGGBRYRjg!-9^?lm3&ZC*bU>KqN!ps}`-<4{2Q6#P@CB3H2v}plLGsTdg zdUA~9j}`HJ0)Dw5RpEt-AD9Km-nE30q;aaJW!{FSy{0M{uJnS6BPb5WbA+gbV|F)) zmIHgx%UWqC|CA#9qGs+8rv2r)U6wjZl^urQq47qqmP>=wM+Pze@Ct^(1S*9>?) ze33MY6I5m!974PjX62ZGy7mZc(yf||2YG7?!H@SI0iuV z;2`LlR4@a5vgH}8isjJItv{eak{k(yNa2wLtr3=i#Z2DepAES#zv0?1roQwSe_A*_ z_(c-Yu&-Rcd#`GftxJg$jMW@`SU9X{T;4FyA=&iul@OSa!~s8kAw3~b$<@eOHq@*A z%1qpd`tF#K=_jZ!!UVa9+}WcM!bIOxZC%H1%()-r#Bf#oogytU3ztny26-c*o_c?6 zT8O{za{X;FbaD6%T!M+@QG+!k1bM9l8VMErPa68GW((8~3) z0v4E)lso76N7SgTIa_#4gR0LHJ>?B+BfVp^@7mrXNZOI}R8T3muHbF+2*ee8z<9==D;DP zc;*+Q)?#*s+hT~+v)}!Cgn9t??*W2~e?o{`W)4CGk~9LWp^v)fOwCT5P~D6ofwPUk zoB|_4?Hb0F)jx27%OUVz-@v0#j0AO&mi*JNR#ZjOtyIW5b;J&cmG!N18K}o7yy?}A zdV_Ip2~;wfKD*QQksM}0T5pmK8ci1zcu<>Ep%gHR0t++0M2DxS(5iN>Ms}&SPIg*o z4^}NYPs=Wn#fucQn_DRt%q5SCshs-t6wdU36`9K2cnu;Ul*$^`nlyKuE6>`K<=g9% z9utv7A+>;-Y=QAC_XCRrqf%GQo|MBkVdjNpu_sEVruo)ncOsWZrfV>Z6OWRrLnfoY zBj07A{xh?(iNE2Qx;EIf^=sY&V3{X{NU^WLsfWwg$-1Q<$mYwqBYGEOZyH3Sh0eyC z1*L!>S(R!L{&_sBxjDm#0Qtf>$|V@+n62ULB@@Z+Ng#2fTC3NAf;lP)5{L3(+>i;DOV6uxMd>LHuR&;PoR(*HYWn4sR=r#EKhG*vyN2>y_%Pp-7 ztL6;9qkViV-NubA>{RlKK|=U7HISo_EnV88AZDvpJ<&s5+Jo|TID408){!8So@~i_ zi-=b!Ql+=@UPw4qV+ZyM>ibgc7mOnB}s2)8M-cJ-+*vCfD zb}VMD8x~+E_xt8S*~E`LeV4Fpm1_&-9n6}mW%KEt6Nu(J-Ff-5k>OTU9sNK9(P@0! ze#jNG34n7TS4jr4=2Gtgb%KjEZ6RFKbg{EdpGONnpyopnK4-EgGHCfC@J|OU`-uR9 zSQuL+&0`;eks3cB`44qFN1CeeSCp&NCRr4{*yW;*@ zBGrUQPYpqK5)bT{8T+uH9&I>jTF=dhAfB)=#n*>4zbq=L(fOVCs*4|eAqb8~uZ38NcOGwlKK%&=u^T#AU+GPimV~L|7rGXx^jxz2; zJa~=nt{%B4un9ooluOL0V=dgA_shZPw@L-K)Tovi#!CJ$HhiGTRSM_RAiqvg#ipJW z0ioEw_vqyKh00td@QS(14_g^^W+{(+Y`sf=2V?lVKt5L|X&o5TKrpybZGA zM|}|rtqR_mu!w&iuomY~^dU8dX$SF8y>CyMsLPZn6m%A7bbyY&1F;yz+N&1Y{lkl; z4Ut0;YyYFNH`CGkPSSXv> z(P!zX`R-UU8IRK$?9wzDZsl+>z4L?%)u|)m1EG_P$CbwfwJ1}Gbq*iV4RBBf8=;-B z3SgqZI7)qH9eqga=9VIIBM4c9$lj?!&#rOH0_O$nNo|&NC3!sPfi8aKJTD`0I=-*< zW~Nxp9CP2%frrszQ>N|;Vm^Y+7~>q#p@&@=z<7gQ$tf-r7KRlHhz3$7t)gUf0Ym6~ z1EBWA+Kd=QPWBsGZ+O<97#-I z%u_OY*lH~T#>Z+vXC}^1h+|vBF8>X%wijaDQHz!Oji@e%7PTQF;apTvyKMQM%K#Qlz2-|dRlHIb$Sc|Jej`O@>z8o(N z{D!(O^%S%#HOLQ%vgd&K6Y3rNmw&zOEZMbFw@3PwE+T%tj|UNB)FJ#ce+0?2g37cb z&0ic{@HPhut>>x%VuRL}8P;S1TtDi#W}u~M9W+ZW;=bHn?a}$CKCTu3IyfiE<-6i7 z?K0R%`=~(wtr0=36^~p%yo%t^H-WiuU4Qx(pcWL7}4O{4={#I1sSWVL z_MiGHB-l!upC>>e2Psp))?OL{0@RS!!*PbMBmorUMc8})bxTMjlYUPukfn468yrax z{@9I>_Lu@%Dke^4Y`CP8G7Z32YYhgS<~%^7BHGk32L4e2dr zK4)A9HrMf&HUp?iTtQ;{UIECAbdyjz;n(T==Mj)PRJb};)=lcFWw9Q0l`xM?P`G!Skn=E z-B{2Rmr>SGjQF9U|9fNI0@8B|op0%Ecf|t!j?`^Xp@Hm6vtBpfy=wG=cP3xwTDY9# z>}9h*v!WoM29r;s%cx>hneRNyFE!!PIneNtI;58fhf7R%m) zRO-!EB9!Z!e{z1;FZyl$m*k<*rK%z{t>*fa8X*nzd0swIE zM9ENy*bi6takw|YNHi@h(?>=C*JcDk2@m^?FZ+KE-PV4yc;n$mdTXG(I0M~qCR<=}Pw;>qHESaF{b2_0N zsjI%)Y{wt|?JyeW0u!R1X?@MCBV7ldk+2IN>eo^|sP{Tl3Hpg}kb3aN)#S#YnQhGc z+YN#(2*>-t!bh1!eE}T=F)bj27$x#N`G^z{R;GbWiX5z-{x`kL`X?&wB+Zh659)kL zu+VmcrNuTwhaq{ms##M_b^2Pt!o&GvzjKM2|56YIoxSL&V^v|sB%V=2um0n`FV%H* zAv;ppr#)8!QdnoF+`AnLNx6(EB~@?5MnCW%mqG+;B&#XsLRZ#7lmQ7m#5Wm4*b&Sy z3u$Zt5wf*iIrB-sIIsFlm(2o>h`jUKc40g;`%OcMk&)YdSEQ+F= zPkS_2D;F8&y;;dH*nM2hgNH-4h1TLJ)$Kwva}~gVTr*lKoh{=C3C}Qqj`%j%j+9fy z5OHq-X>SzAE!G7E?5Oc5mk!*HW2veihmx!f)eX#q`}E9ga%;Is?{h z!d@p7ETIT7W0Ck*{(}ALO|nu9$2XI6y#>~wnsSLBle_2Hv%^(H$*WoG^) zpoeZ>;D{rPd*gZs7}j5~_frTQtK!J~=Q_HA|7Y9Dge91>=lVS2q4hLVZ;Hk|Q!nOa zQmkuw+bG9A)X1b5NJ+kY7gnTb9O9n8UK~282DWGJYu1lrm#d>8UBSxiXF~EFXdW`n z5n$G%vDfamn0FrQJ$e_$E2WWaz%;w4aN27c!Ave3u5qtA)ZoC;|Cm2%9u8F~omw-o zG4kvZLkyK>-Es8TzMOd#Q&*+K3|{>Gb-UraZCct*P+(4^p4d3kWFIDsrs7J1tjr2FfaM0;cU^qGuij@?I^Pco^}<37uNh*W zPLBiT{sQSiZp~6@n4U;0kN`>uIcL!n6Nl?`hFh#_(SCYuUsxhuQq;G#ApdDaAd!$G z)J;?QihbhukMnyik(1o2HC1YA59{}5cp6NW9nO4!Oa1s6HTdudC}kx*r7n5jp~e4n z))bYp+IHb*)L|5Go`-sOk)x?zGo&w8xIbT7{wEw~u9QDe9>^~79WwKhT=0c`kJ zh&cgvyDh}Qme#%|yT8t^1dD?3*aMOx=Ny!*+1N9>3XHvt8>u;=9-#VG2jRSKX+Fak zy|9(N5u^9lVa94g!zFwZ!!VG%*6Q}SMUm!edgSqjo zJs_aeuJHT2&qiAr|pz^R!}1cR0@L>NQRa*##UYxNl^B zqin5L>S%<)sIB?5T-Y@f`e=S=hl{;oJ$X8z35M06K_3Vfi6Wj2auYi?XSwt7pdt~_ z=73gCvFbxPJ|8x!l7Yq%6T?HH2;LAjR}b#|a{GFg{}J~vB;FFZKPh7$T8dc!=J5*^ zB7ARjVu%$HCmZ*L>)(~mD1iXw+Ov`NWcL4d$17#CM0uq2K3^(`dBW)yrVfiS#3|ad{u&Z0dG)tf=1ymRzj(3k=Y#%z(4l zrvIi$NP0ay4B@WpQ~~Yt&n`G#q^8yU5dc*D&N%QN9j6o(ocqgWAfZBL0OO{lCF}r0 zg!G@e+|g!f8b=p>Mcll%VWAyHA`1$jpUFlOA9|&dM!Q&TL(74DE*0%ykyh#P%_vKv z^m%)~r5po6;kr03s=!&QpJV%o(kP*+GJ~2I9(;WO8J)+(*2U@riUP~S%u<)f1OZYG zaO=GPtk$Ok_9&L~$B6k&-aIp_4$Ir47R!8e{;*a&R?K+;UMF<>?4($~j-Rl2l=;@Y z*FS%`LXL;X7Ug1|OZW5aR)4$+6-h@MbxAGW2qAp4G`AMCSSutrMTX@wh=)3OsSdy! z*TcHbocvN26ldQS;(Rl$;f!><<_#Tb^rdk4<^6`1!feUlC@BOBYZS|zNu;wTJ6qM^ zZosmT5VXDpOctvNFis;xD)-m*{KgB$#bZjgzWF%S%8X66?~U7?DD%&5w;ACeKU`bH+J*F}jZ!5G$Ue6}C8! zu}>WD)4_1b4g6w zfG@djh0@!J;bbxf;e+$CD9VjLSZ;BulL+eYA~68J2b3?vo<>j>(f4(%9s*ud*^k>Z zfJmLrg4xu)I&7Hmr6agO%L%6PZQV^G@7afT=Zz5knQ4{%0O%eF)52ZRN>s91ok%u! zqD#At9JCrlJ1lVnj%bsyvk!1}ge2hd1DZ$%0g*V6Gw)TTz!xzao|6b@6D239gphK% z9k5T+Y+;(?oS534A#~;-9Xv1bBy0w;wt-u}KBS=$Wn}eU;{HrcWnLnbz~0zG%c2Rw zRmweke}d6s`FN1u-t7o_qWFBj#vNgSU89|eQDYUOm1{*c&nSF|w18R>1zU9dsc+!~(2jf~&Q+kTC?G^E-8vV^U1WH?OllEe{(`*)# zI*1u3%F5^ZKH6e6$Hv7dJ1XQY;OuOt55h3-LhB{mi?kuJ1 zvt9q2kcGbZvaryD57^Ly=ZN`h zKTl+qIfu{{TcUdWC}cYG-i}9a^%bUqg>r#sK#xV)o>xYIy{5X&)G{tueoCp6hTt{8 z=`pRim4wth6c|YiWY@u8SyMgM1Em3D$CLuErW?>L zV@j`lIJ)z)N(OMlkEYDmLlidrl~P}d6RJ>g#U|xo-uKv8Gn14r2iT0AjV8&5IQ?by zdh+8kZMz=d@bjPPj@n8S?N8SjL?ug=MvxUuNCe@;r9JuFMnm+su$>5C2M=o_7|_-| zDEn5wTW|DMp^f}<{rkST$q)9w_1%}*3hpQB9AUw)=1T=kC5s7n305EA2N3Dz7I#0y zz3t2SAH5oE@j1T~(hab3mqCVfEGCJwKvN*L0C#?ZD~_3J8TlzqjrOTaUe26 K8He%baKcz*oB4hK literal 0 HcmV?d00001 diff --git a/crates/primitives/src/kzg/generated.rs b/crates/primitives/src/kzg/generated.rs new file mode 100644 index 0000000000..597f924660 --- /dev/null +++ b/crates/primitives/src/kzg/generated.rs @@ -0,0 +1,24 @@ +// @generated by build.rs from "src/kzg/trusted_setup.txt", do not modify manually. + +pub use c_kzg::{BYTES_PER_G1_POINT, BYTES_PER_G2_POINT}; + +// Ensure that the build script constants are synced with the C bindings ones. +const _: [(); BYTES_PER_G1_POINT] = [(); 48]; +const _: [(); BYTES_PER_G2_POINT] = [(); 96]; + +pub const NUM_G1_POINTS: usize = 4096; +pub const NUM_G2_POINTS: usize = 65; + +type G1Points = [[u8; BYTES_PER_G1_POINT]; NUM_G1_POINTS]; +type G2Points = [[u8; BYTES_PER_G2_POINT]; NUM_G2_POINTS]; + +pub const G1_POINTS: &G1Points = { + const BYTES: &[u8] = include_bytes!("./g1_points.bin"); + assert!(BYTES.len() == core::mem::size_of::()); + unsafe { &*BYTES.as_ptr().cast::() } +}; +pub const G2_POINTS: &G2Points = { + const BYTES: &[u8] = include_bytes!("./g2_points.bin"); + assert!(BYTES.len() == core::mem::size_of::()); + unsafe { &*BYTES.as_ptr().cast::() } +}; diff --git a/crates/primitives/src/kzg/trusted_setup.txt b/crates/primitives/src/kzg/trusted_setup.txt new file mode 100644 index 0000000000..26612cb887 --- /dev/null +++ b/crates/primitives/src/kzg/trusted_setup.txt @@ -0,0 +1,4163 @@ +4096 +65 +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 +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/crates/primitives/src/kzg/trusted_setup_4.txt b/crates/primitives/src/kzg/trusted_setup_4.txt new file mode 100644 index 0000000000..46b3b86a8b --- /dev/null +++ b/crates/primitives/src/kzg/trusted_setup_4.txt @@ -0,0 +1,71 @@ +4 +65 +91131b2e3c1e5f0b51df8970e67080032f411571b66d301436c46f25bbfddf9ca16756430dc470bdb0d85b47fedcdbc1 +934d35b2a46e169915718b77127b0d4efbacdad7fdde4593af7d21d37ebcb77fe6c8dde6b8a9537854d70ef1f291a585 +9410ca1d0342fe7419f02194281df45e1c1ff42fd8b439de5644cc312815c21ddd2e3eeb63fb807cf837e68b76668bd5 +b163df7e9baeb60f69b6ee5faa538c3a564b62eb8cde6a3616083c8cb2171eedd583c9143e7e916df59bf27da5e024e8 +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 diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 9f9e85b63b..e41ef8b2e8 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -7,6 +7,8 @@ pub mod bytecode; pub mod constants; pub mod db; pub mod env; +#[cfg(feature = "std")] +pub mod kzg; pub mod log; pub mod precompile; pub mod result; @@ -16,20 +18,17 @@ pub mod utilities; pub use bits::B160; pub use bits::B256; -pub use bytes; -pub use bytes::Bytes; -pub use hex; -pub use hex_literal; -/// Address type is last 20 bytes of hash of ethereum account -pub type Address = B160; -/// Hash, in Ethereum usually keccak256. -pub type Hash = B256; - pub use bitvec; pub use bytecode::*; +pub use bytes; +pub use bytes::Bytes; pub use constants::*; pub use env::*; pub use hashbrown::{hash_map, hash_set, HashMap, HashSet}; +pub use hex; +pub use hex_literal; +#[cfg(feature = "std")] +pub use kzg::{EnvKzgSettings, KzgSettings}; pub use log::Log; pub use precompile::*; pub use result::*; @@ -39,3 +38,8 @@ pub use ruint::uint; pub use specification::*; pub use state::*; pub use utilities::*; + +/// Address type is last 20 bytes of hash of ethereum account +pub type Address = B160; +/// Hash, in Ethereum usually keccak256. +pub type Hash = B256; diff --git a/crates/primitives/src/precompile.rs b/crates/primitives/src/precompile.rs index 8456225e0c..a02a86f010 100644 --- a/crates/primitives/src/precompile.rs +++ b/crates/primitives/src/precompile.rs @@ -1,10 +1,13 @@ +use crate::Env; use alloc::vec::Vec; /// A precompile operation result. +/// +/// Returns either `Ok((gas_used, return_bytes))` or `Err(error)`. pub type PrecompileResult = Result<(u64, Vec), PrecompileError>; pub type StandardPrecompileFn = fn(&[u8], u64) -> PrecompileResult; -pub type CustomPrecompileFn = fn(&[u8], u64) -> PrecompileResult; +pub type EnvPrecompileFn = fn(&[u8], u64, env: &Env) -> PrecompileResult; #[derive(Clone, Debug, Eq, PartialEq)] pub enum PrecompileError { @@ -21,4 +24,11 @@ pub enum PrecompileError { Bn128FieldPointNotAMember, Bn128AffineGFailedToCreate, Bn128PairLength, + // Blob errors + /// The input length is not exactly 192 bytes. + BlobInvalidInputLength, + /// The commitment does not match the versioned hash. + BlobMismatchedVersion, + /// The proof verification failed. + BlobVerifyKzgProofFailed, } diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs index c5fcfd3ec0..1355ca47df 100644 --- a/crates/primitives/src/result.rs +++ b/crates/primitives/src/result.rs @@ -122,25 +122,26 @@ impl Output { #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[non_exhaustive] pub enum EVMError { Transaction(InvalidTransaction), - /// REVM specific and related to environment. + /// `prevrandao` is not set for Merge and above. PrevrandaoNotSet, + /// `excess_blob_gas` is not set for Cancun and above. + ExcessBlobGasNotSet, Database(DBError), } #[cfg(feature = "std")] -impl std::error::Error for EVMError where Self: fmt::Debug + fmt::Display {} +impl std::error::Error for EVMError {} -impl fmt::Display for EVMError -where - DBError: fmt::Display, -{ +impl fmt::Display for EVMError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - EVMError::Transaction(v) => write!(f, "Transaction error: {:?}", v), - EVMError::PrevrandaoNotSet => f.write_str("Prevrandao not set"), - EVMError::Database(v) => write!(f, "Database error: {}", v), + EVMError::Transaction(e) => write!(f, "Transaction error: {e:?}"), + EVMError::PrevrandaoNotSet => f.write_str("`prevrandao` not set"), + EVMError::ExcessBlobGasNotSet => f.write_str("`excess_blob_gas` not set"), + EVMError::Database(e) => write!(f, "Database error: {e}"), } } } @@ -180,9 +181,14 @@ pub enum InvalidTransaction { /// EIP-3860: Limit and meter initcode CreateInitcodeSizeLimit, InvalidChainId, - /// Access list is not supported is not supported - /// for blocks before Berlin hardfork. + /// Access list is not supported for blocks before the Berlin hardfork. AccessListNotSupported, + /// `max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork. + MaxFeePerBlobGasNotSupported, + /// `blob_hashes`/`blob_versioned_hashes` is not supported for blocks before the Cancun hardfork. + BlobVersionedHashesNotSupported, + /// Block `blob_gas_price` is greater than tx-specified `max_fee_per_blob_gas` after Cancun. + BlobGasPriceGreaterThanMax, /// System transactions are not supported /// post-regolith hardfork. #[cfg(feature = "optimism")] diff --git a/crates/primitives/src/specification.rs b/crates/primitives/src/specification.rs index 86f3a0f7b6..741271535b 100644 --- a/crates/primitives/src/specification.rs +++ b/crates/primitives/src/specification.rs @@ -1,6 +1,9 @@ #![allow(non_camel_case_types)] -/// SpecId and their activation block +pub use SpecId::*; + +/// Specification IDs and their activation block. +/// /// Information was obtained from: #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, enumn::N)] @@ -21,60 +24,76 @@ pub enum SpecId { LONDON = 12, // London 12965000 ARROW_GLACIER = 13, // Arrow Glacier 13773000 GRAY_GLACIER = 14, // Gray Glacier 15050000 - MERGE = 15, // Paris/Merge TBD (Depends on difficulty) - SHANGHAI = 16, - CANCUN = 17, - LATEST = 18, + MERGE = 15, // Paris/Merge 15537394 (TTD: 58750000000000000000000) + SHANGHAI = 16, // Shanghai 17034870 (TS: 1681338455) + CANCUN = 17, // Cancun TBD #[cfg(feature = "optimism")] BEDROCK = 128, #[cfg(feature = "optimism")] REGOLITH = 129, + LATEST = u8::MAX, } impl SpecId { + #[inline] pub fn try_from_u8(spec_id: u8) -> Option { Self::n(spec_id) } -} -pub use SpecId::*; + #[inline(always)] + pub const fn enabled(our: SpecId, other: SpecId) -> bool { + #[cfg(feature = "optimism")] + { + let (our, other) = (our as u8, other as u8); + let (merge, bedrock, regolith) = + (Self::MERGE as u8, Self::BEDROCK as u8, Self::REGOLITH as u8); + // If the Spec is Bedrock or Regolith, and the input is not Bedrock or Regolith, + // then no hardforks should be enabled after the merge. This is because Optimism's + // Bedrock and Regolith hardforks implement changes on top of the Merge hardfork. + let is_self_optimism = our == bedrock || our == regolith; + let input_not_optimism = other != bedrock && other != regolith; + let after_merge = other > merge; + + if is_self_optimism && input_not_optimism && after_merge { + return false; + } + } + + our as u8 >= other as u8 + } +} impl From<&str> for SpecId { fn from(name: &str) -> Self { match name { - "Frontier" => SpecId::FRONTIER, - "Homestead" => SpecId::HOMESTEAD, - "Tangerine" => SpecId::TANGERINE, - "Spurious" => SpecId::SPURIOUS_DRAGON, - "Byzantium" => SpecId::BYZANTIUM, - "Constantinople" => SpecId::CONSTANTINOPLE, - "Petersburg" => SpecId::PETERSBURG, - "Istanbul" => SpecId::ISTANBUL, - "MuirGlacier" => SpecId::MUIR_GLACIER, - "Berlin" => SpecId::BERLIN, - "London" => SpecId::LONDON, - "Merge" => SpecId::MERGE, - "Shanghai" => SpecId::SHANGHAI, - "Cancun" => SpecId::CANCUN, + "Frontier" => Self::FRONTIER, + "Homestead" => Self::HOMESTEAD, + "Tangerine" => Self::TANGERINE, + "Spurious" => Self::SPURIOUS_DRAGON, + "Byzantium" => Self::BYZANTIUM, + "Constantinople" => Self::CONSTANTINOPLE, + "Petersburg" => Self::PETERSBURG, + "Istanbul" => Self::ISTANBUL, + "MuirGlacier" => Self::MUIR_GLACIER, + "Berlin" => Self::BERLIN, + "London" => Self::LONDON, + "Merge" => Self::MERGE, + "Shanghai" => Self::SHANGHAI, + "Cancun" => Self::CANCUN, #[cfg(feature = "optimism")] "Bedrock" => SpecId::BEDROCK, #[cfg(feature = "optimism")] "Regolith" => SpecId::REGOLITH, - _ => SpecId::LATEST, + _ => Self::LATEST, } } } -impl SpecId { - #[inline] - pub const fn enabled(our: SpecId, other: SpecId) -> bool { - our as u8 >= other as u8 - } -} - pub trait Spec: Sized { + /// The specification ID. const SPEC_ID: SpecId; + /// Returns `true` if the given specification ID is enabled in this spec. #[inline(always)] fn enabled(spec_id: SpecId) -> bool { #[cfg(feature = "optimism")] @@ -97,11 +116,10 @@ pub trait Spec: Sized { } macro_rules! spec { - ($spec_id:tt, $spec_name:tt) => { + ($spec_id:ident, $spec_name:ident) => { pub struct $spec_name; impl Spec for $spec_name { - //specification id const SPEC_ID: SpecId = $spec_id; } }; @@ -125,6 +143,7 @@ spec!(LONDON, LondonSpec); spec!(MERGE, MergeSpec); spec!(SHANGHAI, ShanghaiSpec); spec!(CANCUN, CancunSpec); + spec!(LATEST, LatestSpec); // Optimism Hardforks @@ -157,4 +176,24 @@ mod tests { assert!(RegolithSpec::enabled(SpecId::BEDROCK)); assert!(RegolithSpec::enabled(SpecId::REGOLITH)); } + + #[test] + fn test_bedrock_post_merge_hardforks_spec_id() { + assert!(SpecId::enabled(SpecId::BEDROCK, SpecId::MERGE)); + assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::SHANGHAI)); + assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::CANCUN)); + assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::LATEST)); + assert!(SpecId::enabled(SpecId::BEDROCK, SpecId::BEDROCK)); + assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::REGOLITH)); + } + + #[test] + fn test_regolith_post_merge_hardforks_spec_id() { + assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::MERGE)); + assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::SHANGHAI)); + assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::CANCUN)); + assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::LATEST)); + assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::BEDROCK)); + assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::REGOLITH)); + } } diff --git a/crates/primitives/src/utilities.rs b/crates/primitives/src/utilities.rs index e03be20f6b..3b4aa8fc0f 100644 --- a/crates/primitives/src/utilities.rs +++ b/crates/primitives/src/utilities.rs @@ -1,4 +1,6 @@ -use crate::{B160, B256, U256}; +use crate::{ + B160, B256, BLOB_GASPRICE_UPDATE_FRACTION, MIN_BLOB_GASPRICE, TARGET_BLOB_GAS_PER_BLOCK, U256, +}; use hex_literal::hex; use sha3::{Digest, Keccak256}; @@ -31,6 +33,55 @@ pub fn create2_address(caller: B160, code_hash: B256, salt: U256) -> B160 { B160(hasher.finalize().as_slice()[12..].try_into().unwrap()) } +/// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used` and `excess_blob_gas`. +/// +/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers). +#[inline] +pub fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 { + (parent_excess_blob_gas + parent_blob_gas_used).saturating_sub(TARGET_BLOB_GAS_PER_BLOCK) +} + +/// Calculates the blobfee from the header's excess blob gas field. +/// +/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers). +#[inline] +pub fn calc_blob_fee(excess_blob_gas: u64) -> u64 { + fake_exponential( + MIN_BLOB_GASPRICE, + excess_blob_gas, + BLOB_GASPRICE_UPDATE_FRACTION, + ) +} + +/// Approximates `factor * e ** (numerator / denominator)` using Taylor expansion. +/// +/// This is used to calculate the blob price. +/// +/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers). +/// +/// # Panic +/// +/// Panics if `denominator` is zero. +#[inline] +pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u64 { + assert_ne!(denominator, 0, "attempt to divide by zero"); + let factor = factor as u128; + let numerator = numerator as u128; + let denominator = denominator as u128; + + let mut i = 1; + let mut output = 0; + let mut numerator_accum = factor * denominator; + while numerator_accum > 0 { + output += numerator_accum; + + // Denominator is asserted as not zero at the start of the function. + numerator_accum = (numerator_accum * numerator) / (denominator * i); + i += 1; + } + (output / denominator) as u64 +} + /// Serde functions to serde as [bytes::Bytes] hex string #[cfg(feature = "serde")] pub mod serde_hex_bytes { @@ -59,3 +110,98 @@ pub mod serde_hex_bytes { .map_err(|e| serde::de::Error::custom(e.to_string())) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::GAS_PER_BLOB; + + // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L27 + #[test] + fn test_calc_excess_blob_gas() { + for t @ &(excess, blobs, expected) in &[ + // The excess blob gas should not increase from zero if the used blob + // slots are below - or equal - to the target. + (0, 0, 0), + (0, 1, 0), + (0, TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB, 0), + // If the target blob gas is exceeded, the excessBlobGas should increase + // by however much it was overshot + ( + 0, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 1, + GAS_PER_BLOB, + ), + ( + 1, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 1, + GAS_PER_BLOB + 1, + ), + ( + 1, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 2, + 2 * GAS_PER_BLOB + 1, + ), + // The excess blob gas should decrease by however much the target was + // under-shot, capped at zero. + ( + TARGET_BLOB_GAS_PER_BLOCK, + TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB, + TARGET_BLOB_GAS_PER_BLOCK, + ), + ( + TARGET_BLOB_GAS_PER_BLOCK, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 1, + TARGET_BLOB_GAS_PER_BLOCK - GAS_PER_BLOB, + ), + ( + TARGET_BLOB_GAS_PER_BLOCK, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 2, + TARGET_BLOB_GAS_PER_BLOCK - (2 * GAS_PER_BLOB), + ), + ( + GAS_PER_BLOB - 1, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 1, + 0, + ), + ] { + let actual = calc_excess_blob_gas(excess, blobs * GAS_PER_BLOB); + assert_eq!(actual, expected, "test: {t:?}"); + } + } + + // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L60 + #[test] + fn test_calc_blob_fee() { + for &(excess, expected) in &[(0, 1), (2314057, 1), (2314058, 2), (10 * 1024 * 1024, 23)] { + let actual = calc_blob_fee(excess); + assert_eq!(actual, expected, "test: {excess}"); + } + } + + // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L78 + #[test] + fn fake_exp() { + for t @ &(factor, numerator, denominator, expected) in &[ + (1u64, 0u64, 1u64, 1u64), + (38493, 0, 1000, 38493), + (0, 1234, 2345, 0), + (1, 2, 1, 6), // approximate 7.389 + (1, 4, 2, 6), + (1, 3, 1, 16), // approximate 20.09 + (1, 6, 2, 18), + (1, 4, 1, 49), // approximate 54.60 + (1, 8, 2, 50), + (10, 8, 2, 542), // approximate 540.598 + (11, 8, 2, 596), // approximate 600.58 + (1, 5, 1, 136), // approximate 148.4 + (1, 5, 2, 11), // approximate 12.18 + (2, 5, 2, 23), // approximate 24.36 + (1, 50000000, 2225652, 5709098764), + (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION, 1), + ] { + let actual = fake_exponential(factor, numerator, denominator); + assert_eq!(actual, expected, "test: {t:?}"); + } + } +} diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 2107992b2a..169f3a3a2c 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -29,15 +29,12 @@ ethers-providers = { version = "2.0", optional = true } ethers-core = { version = "2.0", optional = true } futures = { version = "0.3.27", optional = true } -# parallel execution inside state. -rayon = { version = "1.7", optional = true } - [dev-dependencies] hex-literal = "0.4" -ethers-contract = { version = "2.0.9", default-features = false } +ethers-contract = { version = "2.0.10", default-features = false } hex = "0.4.3" anyhow = "1.0.75" -bytes = "1.4.0" +bytes = "1.5.0" criterion = "0.5" [features] @@ -58,7 +55,7 @@ optional_block_gas_limit = ["revm-interpreter/optional_block_gas_limit"] optional_eip3607 = ["revm-interpreter/optional_eip3607"] optional_gas_refund = ["revm-interpreter/optional_gas_refund"] optional_no_base_fee = ["revm-interpreter/optional_no_base_fee"] -std = ["revm-interpreter/std", "rayon"] +std = ["revm-interpreter/std", "revm-precompile/std"] ethersdb = ["std", "tokio", "futures", "ethers-providers", "ethers-core"] serde = ["dep:serde", "dep:serde_json", "revm-interpreter/serde"] arbitrary = ["revm-interpreter/arbitrary"] @@ -70,6 +67,7 @@ optimism = ["revm-interpreter/optimism", "revm-precompile/optimism"] [[example]] name = "fork_ref_transact" path = "../../examples/fork_ref_transact.rs" +required-features = ["ethersdb"] [[bench]] name = "bench" diff --git a/crates/revm/src/db.rs b/crates/revm/src/db.rs index 26b41fc0f7..72f35cc848 100644 --- a/crates/revm/src/db.rs +++ b/crates/revm/src/db.rs @@ -1,15 +1,14 @@ pub mod emptydb; -pub mod in_memory_db; - #[cfg(feature = "ethersdb")] pub mod ethersdb; -#[cfg(feature = "ethersdb")] -pub use ethersdb::EthersDB; - -#[cfg(feature = "std")] +pub mod in_memory_db; pub mod states; -#[cfg(feature = "std")] +pub use crate::primitives::db::*; +pub use emptydb::{EmptyDB, EmptyDBTyped}; +#[cfg(feature = "ethersdb")] +pub use ethersdb::EthersDB; +pub use in_memory_db::*; pub use states::{ AccountRevert, AccountStatus, BundleAccount, BundleState, CacheState, DBBox, OriginalValuesKnown, PlainAccount, RevertToSlot, State, StateBuilder, StateDBBox, @@ -20,8 +19,3 @@ pub use states::{ compile_error!( "`web3db` feature is deprecated, drop-in replacement can be found with feature `ethersdb`" ); - -pub use crate::primitives::db::*; -pub use in_memory_db::*; - -pub use emptydb::{EmptyDB, EmptyDBTyped}; diff --git a/crates/revm/src/db/in_memory_db.rs b/crates/revm/src/db/in_memory_db.rs index 648513c2cc..4909b0bab2 100644 --- a/crates/revm/src/db/in_memory_db.rs +++ b/crates/revm/src/db/in_memory_db.rs @@ -61,7 +61,9 @@ impl CacheDB { pub fn insert_contract(&mut self, account: &mut AccountInfo) { if let Some(code) = &account.code { if !code.is_empty() { - account.code_hash = code.hash_slow(); + if account.code_hash == KECCAK_EMPTY { + account.code_hash = code.hash_slow(); + } self.contracts .entry(account.code_hash) .or_insert_with(|| code.clone()); diff --git a/crates/revm/src/db/states/bundle_account.rs b/crates/revm/src/db/states/bundle_account.rs index 6f4c6fbbc3..d81226a693 100644 --- a/crates/revm/src/db/states/bundle_account.rs +++ b/crates/revm/src/db/states/bundle_account.rs @@ -216,6 +216,7 @@ impl BundleAccount { None } AccountStatus::Destroyed => { + // clear this storage and move it to the Revert. let this_storage = self.storage.drain().collect(); let ret = match self.status { AccountStatus::InMemoryChange | AccountStatus::Changed | AccountStatus::Loaded | AccountStatus::LoadedEmptyEIP161 => { @@ -269,7 +270,7 @@ impl BundleAccount { // and insert it inside revert. let previous_storage = if transition.storage_was_destroyed { - let mut storage = std::mem::take(&mut self.storage) + let mut storage = core::mem::take(&mut self.storage) .into_iter() .map(|t| (t.0, RevertToSlot::Some(t.1.present_value))) .collect::>(); diff --git a/crates/revm/src/db/states/bundle_state.rs b/crates/revm/src/db/states/bundle_state.rs index 4c13aa8698..f2965a51a0 100644 --- a/crates/revm/src/db/states/bundle_state.rs +++ b/crates/revm/src/db/states/bundle_state.rs @@ -3,13 +3,15 @@ use super::{ reverts::{AccountInfoRevert, Reverts}, AccountRevert, AccountStatus, BundleAccount, PlainStateReverts, RevertToSlot, TransitionState, }; -use rayon::slice::ParallelSliceMut; +use alloc::{ + collections::{BTreeMap, BTreeSet}, + vec::Vec, +}; +use core::ops::RangeInclusive; use revm_interpreter::primitives::{ hash_map::{self, Entry}, - AccountInfo, Bytecode, HashMap, StorageSlot, B160, B256, KECCAK_EMPTY, U256, + AccountInfo, Bytecode, HashMap, HashSet, StorageSlot, B160, B256, KECCAK_EMPTY, U256, }; -use std::collections::{BTreeMap, BTreeSet, HashSet}; -use std::ops::RangeInclusive; /// This builder is used to help to facilitate the initialization of `BundleState` struct #[derive(Debug)] @@ -438,8 +440,8 @@ impl BundleState { self.reverts.push(reverts); } - /// Consume the bundle state and return sorted plain state. - pub fn into_plain_state_sorted(self, is_value_known: OriginalValuesKnown) -> StateChangeset { + /// Consume the bundle state and return plain state. + pub fn into_plain_state(self, is_value_known: OriginalValuesKnown) -> StateChangeset { // pessimistically pre-allocate assuming _all_ accounts changed. let state_len = self.state.len(); let mut accounts = Vec::with_capacity(state_len); @@ -476,27 +478,21 @@ impl BundleState { } } - if !account_storage_changed.is_empty() { - account_storage_changed.sort_by(|a, b| a.0.cmp(&b.0)); + if !account_storage_changed.is_empty() || was_destroyed { // append storage changes to account. storage.push(PlainStorageChangeset { address, + wipe_storage: was_destroyed, storage: account_storage_changed, }); } } - - accounts.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); - storage.par_sort_unstable_by(|a, b| a.address.cmp(&b.address)); - - let mut contracts = self + let contracts = self .contracts .into_iter() // remove empty bytecodes .filter(|(b, _)| *b != KECCAK_EMPTY) .collect::>(); - contracts.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); - StateChangeset { accounts, storage, @@ -505,12 +501,12 @@ impl BundleState { } /// Consume the bundle state and split it into reverts and plain state. - pub fn into_sorted_plain_state_and_reverts( + pub fn into_plain_state_and_reverts( mut self, is_value_known: OriginalValuesKnown, ) -> (StateChangeset, PlainStateReverts) { let reverts = self.take_all_reverts(); - let plain_state = self.into_plain_state_sorted(is_value_known); + let plain_state = self.into_plain_state(is_value_known); (plain_state, reverts.into_plain_state_reverts()) } diff --git a/crates/revm/src/db/states/cache.rs b/crates/revm/src/db/states/cache.rs index 4d0a215cbe..9dc8d98642 100644 --- a/crates/revm/src/db/states/cache.rs +++ b/crates/revm/src/db/states/cache.rs @@ -1,7 +1,9 @@ use super::{ plain_account::PlainStorage, transition_account::TransitionAccount, CacheAccount, PlainAccount, }; +use alloc::vec::Vec; use revm_interpreter::primitives::{AccountInfo, Bytecode, HashMap, State as EVMState, B160, B256}; + /// Cache state contains both modified and original values. /// /// Cache state is main state that revm uses to access state. diff --git a/crates/revm/src/db/states/changes.rs b/crates/revm/src/db/states/changes.rs index 99411b7b8c..34519f65bd 100644 --- a/crates/revm/src/db/states/changes.rs +++ b/crates/revm/src/db/states/changes.rs @@ -1,17 +1,20 @@ use super::RevertToSlot; +use alloc::vec::Vec; use revm_interpreter::primitives::{AccountInfo, Bytecode, B160, B256, U256}; -/// Sorted accounts/storages/contracts for inclusion into database. +/// accounts/storages/contracts for inclusion into database. /// Structure is made so it is easier to apply directly to database /// that mostly have separate tables to store account/storage/contract data. +/// +/// Note: that data is **not** sorted. Some database benefit of faster inclusion +/// and smaller footprint if data is inserted in sorted order. #[derive(Clone, Debug, Default)] pub struct StateChangeset { - /// Vector of account presorted by address, with removed contracts bytecode + /// Vector of **not** sorted accounts information. pub accounts: Vec<(B160, Option)>, - /// Vector of storage presorted by address - /// First bool is indicator if storage needs to be dropped. + /// Vector of **not** sorted storage. pub storage: Vec, - /// Vector of contracts presorted by bytecode hash + /// Vector of contracts by bytecode hash. **not** sorted. pub contracts: Vec<(B256, Bytecode)>, } @@ -21,6 +24,8 @@ pub struct StateChangeset { pub struct PlainStorageChangeset { /// Address of account pub address: B160, + /// Wipe storage, + pub wipe_storage: bool, /// Storage key value pairs. pub storage: Vec<(U256, U256)>, } @@ -35,20 +40,20 @@ pub struct PlainStorageRevert { /// state of this storage from database (And moving it to revert). pub wiped: bool, /// Contains the storage key and old values of that storage. - /// Assume they are sorted by the key. + /// Reverts are **not** sorted. pub storage_revert: Vec<(U256, RevertToSlot)>, } /// Plain state reverts are used to easily store reverts into database. /// -/// Note that accounts are assumed sorted by address. +/// Note that accounts are assumed **not** sorted. #[derive(Clone, Debug, Default)] pub struct PlainStateReverts { - /// Vector of account presorted by address, with removed contracts bytecode + /// Vector of account with removed contracts bytecode /// - /// Note: AccountInfo None means that account needs to be removed. + /// Note: If AccountInfo is None means that account needs to be removed. pub accounts: Vec)>>, - /// Vector of storage presorted by address + /// Vector of storage with its address. pub storage: Vec>, } diff --git a/crates/revm/src/db/states/reverts.rs b/crates/revm/src/db/states/reverts.rs index b5b2b4cf1c..c4b1346708 100644 --- a/crates/revm/src/db/states/reverts.rs +++ b/crates/revm/src/db/states/reverts.rs @@ -2,8 +2,8 @@ use super::{ changes::PlainStorageRevert, AccountStatus, BundleAccount, PlainStateReverts, StorageWithOriginalValues, }; +use alloc::vec::Vec; use core::ops::{Deref, DerefMut}; -use rayon::slice::ParallelSliceMut; use revm_interpreter::primitives::{AccountInfo, HashMap, B160, U256}; /// Contains reverts of multiple account in multiple transitions (Transitions as a block). @@ -58,17 +58,13 @@ impl Reverts { AccountInfoRevert::DoNothing => (), } if revert_account.wipe_storage || !revert_account.storage.is_empty() { - let mut account_storage = - revert_account.storage.into_iter().collect::>(); - account_storage.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); storage.push(PlainStorageRevert { address, wiped: revert_account.wipe_storage, - storage_revert: account_storage, + storage_revert: revert_account.storage.into_iter().collect::>(), }); } } - accounts.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); state_reverts.accounts.push(accounts); state_reverts.storage.push(storage); } diff --git a/crates/revm/src/db/states/state.rs b/crates/revm/src/db/states/state.rs index 3ff9f81960..140145c7c5 100644 --- a/crates/revm/src/db/states/state.rs +++ b/crates/revm/src/db/states/state.rs @@ -1,9 +1,13 @@ use super::{ bundle_state::BundleRetention, cache::CacheState, plain_account::PlainStorage, BundleState, - CacheAccount, TransitionState, + CacheAccount, StateBuilder, TransitionAccount, TransitionState, +}; +use crate::db::EmptyDB; +use alloc::{ + boxed::Box, + collections::{btree_map, BTreeMap}, + vec::Vec, }; -use crate::{db::EmptyDB, StateBuilder, TransitionAccount}; -use alloc::collections::{btree_map, BTreeMap}; use revm_interpreter::primitives::{ db::{Database, DatabaseCommit}, hash_map, Account, AccountInfo, Bytecode, HashMap, B160, B256, BLOCK_HASH_HISTORY, U256, @@ -189,12 +193,18 @@ impl State { } } + // TODO make cache aware of transitions dropping by having global transition counter. /// Takes changeset and reverts from state and replaces it with empty one. /// This will trop pending Transition and any transitions would be lost. /// - /// TODO make cache aware of transitions dropping by having global transition counter. + /// NOTE: If either: + /// * The [State] has not been built with [StateBuilder::with_bundle_update], or + /// * The [State] has a [TransitionState] set to `None` when + /// [TransitionState::merge_transitions] is called, + /// + /// this will panic. pub fn take_bundle(&mut self) -> BundleState { - std::mem::take(self.bundle_state.as_mut().unwrap()) + core::mem::take(self.bundle_state.as_mut().unwrap()) } } diff --git a/crates/revm/src/db/states/transition_state.rs b/crates/revm/src/db/states/transition_state.rs index a22c34af2d..f4d9829fcd 100644 --- a/crates/revm/src/db/states/transition_state.rs +++ b/crates/revm/src/db/states/transition_state.rs @@ -1,4 +1,5 @@ use super::TransitionAccount; +use alloc::vec::Vec; use revm_interpreter::primitives::{hash_map::Entry, HashMap, B160}; #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 1173bde099..a430249f94 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -65,16 +65,18 @@ struct CallResult { } pub trait Transact { - /// Do checks that could make transaction fail before call/create + /// Run checks that could make transaction fail before call/create. fn preverify_transaction(&mut self) -> Result<(), EVMError>; - /// Skip preverification steps and do transaction + /// Skip pre-verification steps and execute the transaction. fn transact_preverified(&mut self) -> EVMResult; - /// Do transaction. - /// InstructionResult InstructionResult, Output for call or Address if we are creating - /// contract, gas spend, gas refunded, State that needs to be applied. - fn transact(&mut self) -> EVMResult; + /// Execute transaction by running pre-verification steps and then transaction itself. + #[inline] + fn transact(&mut self) -> EVMResult { + self.preverify_transaction() + .and_then(|_| self.transact_preverified()) + } } impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, INSPECT> { @@ -155,29 +157,33 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact fn preverify_transaction(&mut self) -> Result<(), EVMError> { let env = self.env(); + // Important: validate block before tx. env.validate_block_env::()?; env.validate_tx::()?; - let tx_caller = env.tx.caller; - let tx_data = &env.tx.data; - let tx_is_create = env.tx.transact_to.is_create(); - - let initial_gas_spend = initial_tx_gas::(tx_data, tx_is_create, &env.tx.access_list); + let initial_gas_spend = initial_tx_gas::( + &env.tx.data, + env.tx.transact_to.is_create(), + &env.tx.access_list, + ); // Additonal check to see if limit is big enought to cover initial gas. - if env.tx.gas_limit < initial_gas_spend { + if initial_gas_spend > env.tx.gas_limit { return Err(InvalidTransaction::CallGasCostMoreThanGasLimit.into()); } // load acc - let journal = &mut self.data.journaled_state; - let (caller_account, _) = journal + let tx_caller = env.tx.caller; + let (caller_account, _) = self + .data + .journaled_state .load_account(tx_caller, self.data.db) .map_err(EVMError::Database)?; - self.data.env.validate_tx_against_state(caller_account)?; - - Ok(()) + self.data + .env + .validate_tx_against_state(caller_account) + .map_err(Into::into) } fn transact_preverified(&mut self) -> EVMResult { @@ -186,8 +192,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let tx_value = env.tx.value; let tx_data = env.tx.data.clone(); let tx_gas_limit = env.tx.gas_limit; - let tx_is_create = env.tx.transact_to.is_create(); - let effective_gas_price = env.effective_gas_price(); #[cfg(feature = "optimism")] let (tx_mint, tx_system, tx_l1_cost, is_deposit, l1_block_info) = { @@ -218,8 +222,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact ) }; - let initial_gas_spend = - initial_tx_gas::(&tx_data, tx_is_create, &env.tx.access_list); + let initial_gas_spend = initial_tx_gas::( + &tx_data, + env.tx.transact_to.is_create(), + &env.tx.access_list, + ); // load coinbase // EIP-3651: Warm COINBASE. Starts the `COINBASE` address warm @@ -229,7 +236,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact .initial_account_load(self.data.env.block.coinbase, &[], self.data.db) .map_err(EVMError::Database)?; } + self.load_access_list()?; + // Without this line, the borrow checker complains that `self` is borrowed mutable above. + let env = &self.data.env; // load acc let journal = &mut self.data.journaled_state; @@ -259,13 +269,17 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact .load_account(tx_caller, self.data.db) .map_err(EVMError::Database)?; - // Reduce gas_limit*gas_price amount of caller account. - // unwrap_or can only occur if disable_balance_check is enabled - caller_account.info.balance = caller_account - .info - .balance - .checked_sub(U256::from(tx_gas_limit).saturating_mul(effective_gas_price)) - .unwrap_or(U256::ZERO); + // Subtract gas costs from the caller's account. + // We need to saturate the gas cost to prevent underflow in case that `disable_balance_check` is enabled. + let mut gas_cost = U256::from(tx_gas_limit).saturating_mul(env.effective_gas_price()); + + // EIP-4844 + if GSPEC::enabled(CANCUN) { + let data_fee = env.calc_data_fee().expect("already checked"); + gas_cost = gas_cost.saturating_add(U256::from(data_fee)); + } + + caller_account.info.balance = caller_account.info.balance.saturating_sub(gas_cost); // touch account so we know it is changed. caller_account.mark_touch(); @@ -276,8 +290,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let (exit_reason, ret_gas, output) = match self.data.env.tx.transact_to { TransactTo::Call(address) => { // Nonce is already checked - caller_account.info.nonce = - caller_account.info.nonce.checked_add(1).unwrap_or(u64::MAX); + caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); let (exit, gas, bytes) = self.call(&mut CallInputs { contract: address, @@ -396,11 +409,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact Ok(ResultAndState { result, state }) } - - fn transact(&mut self) -> EVMResult { - self.preverify_transaction() - .and_then(|_| self.transact_preverified()) - } } impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, INSPECT> { @@ -553,6 +561,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, (new_state, logs, gas_used, gas_refunded) } + #[inline(never)] fn prepare_create(&mut self, inputs: &CreateInputs) -> Result { let gas = Gas::new(inputs.gas_limit); @@ -809,7 +818,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, .expect("Check for precompile should be already done"); let out = match precompile { Precompile::Standard(fun) => fun(input_data, gas.limit()), - Precompile::Custom(fun) => fun(input_data, gas.limit()), + Precompile::Env(fun) => fun(input_data, gas.limit(), self.env()), }; match out { Ok((gas_used, data)) => { @@ -842,6 +851,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, } } + #[inline(never)] fn prepare_call(&mut self, inputs: &CallInputs) -> Result { let gas = Gas::new(inputs.gas_limit); let account = match self diff --git a/crates/revm/src/inspector/tracer_eip3155.rs b/crates/revm/src/inspector/tracer_eip3155.rs index 463fd3ce4a..cd8ff0f3b8 100644 --- a/crates/revm/src/inspector/tracer_eip3155.rs +++ b/crates/revm/src/inspector/tracer_eip3155.rs @@ -65,7 +65,6 @@ impl Inspector for TracerEip3155 { self.opcode = interp.current_opcode(); self.mem_size = interp.memory.len(); self.gas = self.gas_inspector.gas_remaining(); - // InstructionResult::Continue } diff --git a/documentation/src/SUMMARY.md b/documentation/src/SUMMARY.md index de50a57ba7..9cc423b5b3 100644 --- a/documentation/src/SUMMARY.md +++ b/documentation/src/SUMMARY.md @@ -4,6 +4,7 @@ - [Revm](./crates/revm.md) - [evm](./crates/revm/evm.md) - [evm_impl](./crates/revm/evm_impl.md) + - [The Host Trait](./crates/revm/host_trait.md) - [inspector](./crates/revm/inspector.md) - [journaled_state](./crates/revm/journaled_state.md) - [Interpreter](./crates/interpreter.md) diff --git a/documentation/src/crates/interpreter.md b/documentation/src/crates/interpreter.md index 3146c282ee..10fcca0f6c 100644 --- a/documentation/src/crates/interpreter.md +++ b/documentation/src/crates/interpreter.md @@ -5,7 +5,7 @@ The `interpreter` crate is concerned with the execution of the EVM opcodes and s Modules: - [gas](./interpreter/gas.md): This module deals with handling the gas mechanics in the EVM, such as calculating gas costs for operations. -- [host](./interpreter/host.md): This module defines the evm context `Host` trait. +- [host](./interpreter/host.md): This module defines the EVM context `Host` trait. - [inner_models](./interpreter/inner_models.md): This module contains the inner data structures used in the EVM implementation. - [instruction_result](./interpreter/instruction_result.md): This module contains definitions related to the result of instruction execution. - [instructions](./interpreter/instructions.md): This module includes the definitions of the EVM opcodes (instructions). @@ -13,13 +13,13 @@ Modules: External Crates: -- alloc: The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. -- core: The core crate is the dependency-free foundation of the Rust standard library. It includes fundamental types, macros, and traits. +- [alloc](https://doc.rust-lang.org/alloc/): The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. +- [core](https://doc.rust-lang.org/core/): The core crate is the dependency-free foundation of the Rust standard library. It includes fundamental types, macros, and traits. Constants: -- `USE_GAS`: This constant determines whether gas measurement should be used. It's set to false if the `no_gas_measuring` feature is enabled. +- `USE_GAS`: This constant determines whether gas measurement should be enabled. It's set to false if the `no_gas_measuring` feature is enabled. Re-exports: - Several types and functions are re-exported for easier access by users of this library, such as `Gas`, `Host`, `InstructionResult`, `OpCode`, `Interpreter`, `Memory`, `Stack`, and others. This allows users to import these items directly from the library root instead of from their individual modules. -- revm_primitives: This crate is re-exported, providing primitive types or functionality used in the EVM implementation. +- `revm_primitives`: This crate is re-exported, providing primitive types or functionality used in the EVM implementation. diff --git a/documentation/src/crates/precompile.md b/documentation/src/crates/precompile.md index ff0932d3b1..cae13c8f50 100644 --- a/documentation/src/crates/precompile.md +++ b/documentation/src/crates/precompile.md @@ -1,12 +1,12 @@ # Precompile -The `precompile` crate contains the implementation of the Ethereum precompile opcodes in the evm. Precompiles are a shortcut to execute a function implemented by the EVM itself, rather than an actual contract. Precompiled contracts are essentially predefined smart contracts on Ethereum, residing at hardcoded addresses and used for computationally heavy operations that are cheaper when implemented this way. There are 6 precompiles implemented in REVM, and they are: `blake2`, `bn128` curve, `identity`, `secp256k1`, `modexp`, and `sha256` and `ripemd160` has functions. +The `precompile` crate contains the implementation of the Ethereum precompile opcodes in the EVM. Precompiles are a shortcut to execute a function implemented by the EVM itself, rather than an actual contract. Precompiled contracts are essentially predefined smart contracts on Ethereum, residing at hardcoded addresses and used for computationally heavy operations that are cheaper when implemented this way. There are 6 precompiles implemented in REVM, and they are: `blake2`, `bn128` curve, `identity`, `secp256k1`, `modexp`, and `sha256` and `ripemd160` hash functions. Modules: - [blake2](./precompile/blake2.md): This module implements the `BLAKE2` compression function, as specified in EIP-152. - [bn128](./precompile/bn128.md): This module contains the implementations of precompiled contracts for addition, scalar multiplication, and optimal ate pairing check on the alt_bn128 elliptic curve. -- [hash](./precompile/hash.md): This module includes the implementations for the SHA256 and RIPEMD160 hash function precompiles. +- [hash](./precompile/hash.md): This module includes the implementations for the `SHA256` and `RIPEMD160` hash function precompiles. - [identity](./precompile/identity.md): This module implements the Identity precompile, which returns the input data unchanged. - [modexp](./precompile/modexp.md): This module implements the big integer modular exponentiation precompile. - [secp256k1](./precompile/secp256k1.md): This module implements the ECDSA public key recovery precompile, based on the secp256k1 curve. @@ -29,8 +29,8 @@ Functions: External Crates: -- alloc: The alloc crate provides types for heap allocation, and is used here for the `Vec` type. -- core: The core crate provides fundamental Rust types, macros, and traits, and is used here for `fmt::Result`. +- [alloc](https://doc.rust-lang.org/alloc/): The alloc crate provides types for heap allocation, and is used here for the `Vec` type. +- [core](https://doc.rust-lang.org/core/): The core crate provides fundamental Rust types, macros, and traits, and is used here for `fmt::Result`. Re-exported Crates and Types: diff --git a/documentation/src/crates/precompile/point_evaluation.md b/documentation/src/crates/precompile/point_evaluation.md index 1b69919280..4622af6126 100644 --- a/documentation/src/crates/precompile/point_evaluation.md +++ b/documentation/src/crates/precompile/point_evaluation.md @@ -3,4 +3,4 @@ This precompile is introduced in [EIP4844](https://eips.ethereum.org/EIPS/eip-4844) and is used to verify KZG commitments of blobspace. The precompile allows for efficient verification of commitments to blog transactions. The blob-space transaction contains a large amount of data that cannot be accessed by EVM execution, but has a commitment that can be accessed and verified. The EIP is designed to be forward compatible with danksharding architecture while giving L2s access to cheaper L1 commitments. This precompiled contract resides at the hardcoded Ethereum address `0x000000000000000000000000000000000000000A`. -A useful resource is the python refrence implementation for the precompile, which can be found [here](https://github.com/ethereum/consensus-specs/blob/86fb82b221474cc89387fa6436806507b3849d88/specs/deneb/polynomial-commitments.md). This implementation uses the [c-kzg](https://github.com/ethereum/c-kzg-4844) audited foriegn function interface bindings from the Ethereum Foundation. \ No newline at end of file +A useful resource is the python refrence implementation for the precompile, which can be found [here](https://github.com/ethereum/consensus-specs/blob/86fb82b221474cc89387fa6436806507b3849d88/specs/deneb/polynomial-commitments.md). This implementation uses the [c-kzg](https://github.com/ethereum/c-kzg-4844) audited foreign function interface bindings from the Ethereum Foundation. \ No newline at end of file diff --git a/documentation/src/crates/revm/evm_impl.md b/documentation/src/crates/revm/evm_impl.md index 08d849e61b..2aa388b4bc 100644 --- a/documentation/src/crates/revm/evm_impl.md +++ b/documentation/src/crates/revm/evm_impl.md @@ -1,6 +1,8 @@ # EVM Implementation -This module implements the Ethereum Virtual Machine (EVM), a stack-based virtual machine that executes Ethereum smart contracts. +This module implements the Ethereum Virtual Machine (EVM), a stack-based virtual machine that executes Ethereum smart contracts. The following methods are exposed through the `EVMImpl` struct. + +## Methods - `run_interpreter` @@ -30,63 +32,4 @@ This module implements the Ethereum Virtual Machine (EVM), a stack-based virtual - `inputs`: A mutable reference to a `CallInputs` instance, which contains all the necessary information for the contract call. - The method returns a tuple containing the result of the call (as an `InstructionResult`), the remaining gas (as a `Gas` instance), and any output data from the call (as a `Bytes` instance). - -## Host Implementation - -The `Host` trait provides an interface that allows the EVM to interact with the external world. It contains methods to access environmental information, manipulate account balances, and interact with contract code and storage. - -The `EVMImpl` struct implements this `Host` trait. - -- `step` & `step_end` - - These methods are used to control the interpreter's execution. They move the interpreter forward one step, allowing the user to inspect the state of the interpreter after each individual operation. - These control the execution of the interpreter, allowing step-by-step execution and inspection. - -- `env` - - This method returns a mutable reference to the environment information that the EVM uses for its execution. The `Env` struct contains details about the current block, such as the timestamp, block number, difficulty, and gas limit. - -- `block_hash` - - This method retrieves the hash of a block given its number. It's typically used within smart contracts for actions like random number generation. - -- `load_account` - - This method loads the account associated with a given address and returns information about the account's existence and if it's a contract. - -- `balance` - - This method retrieves the balance of an Ethereum account given its address. It returns a tuple containing the balance and a boolean indicating whether the account was "cold" (accessed for the first time in the current transaction). - -- `code` - - This method retrieves the bytecode of a given address. It returns a tuple containing the bytecode and a boolean indicating whether the account was "cold". - -- `code_hash` - - This method retrieves the code_hash at a given address. It returns a tuple containing the hash and a boolean indicating whether the account was "cold". - -- `sload` & `sstore` - - These methods interact with the contract storage. The `sload` method retrieves a value from contract storage, while `sstore` sets a value in contract storage. - -- `tload` & `tstore` - - As defined in [EIP1153](https://eips.ethereum.org/EIPS/eip-1153), for transiant storage reads and writes. - -- `log` - - This method is used to create log entries, which are a way for contracts to produce output that external observers (like dapps or the frontend of a blockchain explorer) can listen for and react to. - -- `selfdestruct` - - The selfdestruct method attempts to terminate the specified address, transferring its remaining balance to a given target address. If the INSPECT constant is true, the self-destruction event is observed or logged via an inspector. The method returns an Option, encapsulating the outcome of the operation: Some(SelfDestructResult) on success and None if an error occurs, with the error being stored internally for later reference. - -- `create` - - The create method initiates the creation of a contract with the provided CreateInputs. If the INSPECT constant is true, the creation process is observed or logged using an inspector, both at the start and end of the creation. The method returns a tuple consisting of the operation's result (InstructionResult), the optional address (Option) of the newly created contract, the amount of gas consumed (Gas), and the output data (Bytes). If the inspector intervenes and determines the instruction shouldn't continue, an early return occurs with the observed outcomes. - -- `call` - - The call method manages a contract invocation using the provided CallInputs. If the INSPECT constant is active, the call event is observed or logged via an inspector before execution. The method yields a tuple representing the outcome of the call: the result status (InstructionResult), the consumed gas (Gas), and the output data (Bytes). If the inspector suggests early termination, the method returns immediately with the observed results. Otherwise, the main call execution is processed, and the outcomes, either raw or observed, are returned accordingly. \ No newline at end of file + The method returns a tuple containing the result of the call (as an `InstructionResult`), the remaining gas (as a `Gas` instance), and any output data from the call (as a `Bytes` instance). \ No newline at end of file diff --git a/documentation/src/crates/revm/host_trait.md b/documentation/src/crates/revm/host_trait.md new file mode 100644 index 0000000000..697a2b8126 --- /dev/null +++ b/documentation/src/crates/revm/host_trait.md @@ -0,0 +1,57 @@ +# Host Implementation + +The `Host` trait provides an interface that allows the EVM to interact with the external world. It contains methods to access environmental information, manipulate account balances, and interact with contract code and storage. + +The [`EVMImpl`](./evm_impl.md) struct implements this `Host` trait. + +- `step` & `step_end` + + These methods are used to control the interpreter's execution. They move the interpreter forward one step, allowing the user to inspect the state of the interpreter after each individual operation. These control the execution of the interpreter, allowing step-by-step execution and inspection. + +- `env` + + This method returns a mutable reference to the environment information that the EVM uses for its execution. The `Env` struct contains details about the current block, such as the timestamp, block number, difficulty, and gas limit. + +- `block_hash` + + This method retrieves the hash of a block given its number. It's typically used within smart contracts for actions like random number generation. + +- `load_account` + + This method loads the account associated with a given address and returns information about the account's existence and if it's a contract. + +- `balance` + + This method retrieves the balance of an Ethereum account given its address. It returns a tuple containing the balance and a boolean indicating whether the account was "cold" (accessed for the first time in the current transaction). + +- `code` + + This method retrieves the bytecode of a given address. It returns a tuple containing the bytecode and a boolean indicating whether the account was "cold". + +- `code_hash` + + This method retrieves the code_hash at a given address. It returns a tuple containing the hash and a boolean indicating whether the account was "cold". + +- `sload` & `sstore` + + These methods interact with the contract storage. The `sload` method retrieves a value from contract storage, while `sstore` sets a value in contract storage. + +- `tload` & `tstore` + + As defined in [EIP1153](https://eips.ethereum.org/EIPS/eip-1153), for transiant storage reads and writes. + +- `log` + + This method is used to create log entries, which are a way for contracts to produce output that external observers (like dapps or the frontend of a blockchain explorer) can listen for and react to. + +- `selfdestruct` + + The selfdestruct method attempts to terminate the specified address, transferring its remaining balance to a given target address. If the INSPECT constant is true, the self-destruction event is observed or logged via an inspector. The method returns an Option, encapsulating the outcome of the operation: Some(SelfDestructResult) on success and None if an error occurs, with the error being stored internally for later reference. + +- `create` + + The create method initiates the creation of a contract with the provided CreateInputs. If the INSPECT constant is true, the creation process is observed or logged using an inspector, both at the start and end of the creation. The method returns a tuple consisting of the operation's result (InstructionResult), the optional address (Option) of the newly created contract, the amount of gas consumed (Gas), and the output data (Bytes). If the inspector intervenes and determines the instruction shouldn't continue, an early return occurs with the observed outcomes. + +- `call` + + The call method manages a contract invocation using the provided CallInputs. If the INSPECT constant is active, the call event is observed or logged via an inspector before execution. The method yields a tuple representing the outcome of the call: the result status (InstructionResult), the consumed gas (Gas), and the output data (Bytes). If the inspector suggests early termination, the method returns immediately with the observed results. Otherwise, the main call execution is processed, and the outcomes, either raw or observed, are returned accordingly. \ No newline at end of file diff --git a/documentation/src/crates/revm/journaled_state.md b/documentation/src/crates/revm/journaled_state.md index aa36a59f77..853f43d5d1 100644 --- a/documentation/src/crates/revm/journaled_state.md +++ b/documentation/src/crates/revm/journaled_state.md @@ -1,21 +1,8 @@ # Journaled State -The `journaled_state` module of the `revm` crate provides a state management -implementation for Ethereum-style accounts. It includes support for -various actions such as self-destruction of accounts, initial account loading, account state -modification, and logging. It also contains several important utility functions such as -`is_precompile`. -This module is built around the `JournaledState` structure, which encapsulates the entire -state of the blockchain. `JournaledState` uses an internal state representation (a HashMap) -that tracks all accounts. Each account is represented by the `Account` structure, which includes -fields like balance, nonce, and code hash. -For state-changing operations, the module keeps track of all the changes within a "journal" for -easy reversion and commitment to the database. This feature is particularly useful for handling -reversion of state changes in case of transaction failures or other exceptions. -The module interacts with a database through the `Database` trait, which abstracts the -operations for fetching and storing data. This design allows for a pluggable backend -where different implementations of the `Database` trait can be used to persist the state -in various ways (for instance, in-memory or disk-based databases). +The `journaled_state` module of the `revm` crate provides a state management implementation for Ethereum-style accounts. It includes support for various actions such as self-destruction of accounts, initial account loading, account state modification, and logging. It also contains several important utility functions such as `is_precompile`. + +This module is built around the `JournaledState` structure, which encapsulates the entire state of the blockchain. `JournaledState` uses an internal state representation (a `HashMap`) that tracks all accounts. Each account is represented by the `Account` structure, which includes fields like balance, nonce, and code hash. For state-changing operations, the module keeps track of all the changes within a "journal" for easy reversion and commitment to the database. This feature is particularly useful for handling reversion of state changes in case of transaction failures or other exceptions. The module interacts with a database through the `Database` trait, which abstracts the operations for fetching and storing data. This design allows for a pluggable backend where different implementations of the `Database` trait can be used to persist the state in various ways (for instance, in-memory or disk-based databases). ## Data Structures diff --git a/documentation/src/introduction.md b/documentation/src/introduction.md index 5102855f8e..aa8e5ae880 100644 --- a/documentation/src/introduction.md +++ b/documentation/src/introduction.md @@ -1,10 +1,10 @@ # Introduction -`revm` is an Ethereum Virtual Machine (EVM) written in Rust that is focused on speed and simplicity. This documentation is very much a work in progress and a community effort. If you would like to contribute and improve these docs please make a pr to the [github repo](https://github.com/bluealloy/revm/tree/main). Importantly Revm is just the execution environment for ethereum, there is no networking or consensus related work in this repository. +`revm` is an Ethereum Virtual Machine (EVM) written in Rust that is focused on speed and simplicity. This documentation is very much a work in progress and a community effort. If you would like to contribute and improve these docs please make a pr to the [github repo](https://github.com/bluealloy/revm/tree/main). Most importantly, Revm is just the execution environment for ethereum; there is no networking or consensus related work in this repository. ## Crates -The project has 4 main crates that are used to build the revm. The crates are: +The project has 4 main crates that are used to build revm. These are: - `revm`: The main EVM library. - `primitives`: Primitive data types. From feec29a0f0d47aa7a7186b839b1dfa23348ec7be Mon Sep 17 00:00:00 2001 From: rakita Date: Fri, 22 Sep 2023 23:03:45 +0200 Subject: [PATCH 50/55] Introduce call return handler --- crates/interpreter/src/gas.rs | 198 ----------------------------- crates/revm/src/evm_impl.rs | 57 ++------- crates/revm/src/handlers.rs | 230 ++++++++++++++++++++++++++++++++++ crates/revm/src/lib.rs | 1 + 4 files changed, 241 insertions(+), 245 deletions(-) create mode 100644 crates/revm/src/handlers.rs diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index 0e7fcbfb34..79d6f3905d 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -95,85 +95,6 @@ impl Gas { true } - /// Consume the revert gas. - #[cfg(not(feature = "optimism"))] - #[inline] - pub fn consume_revert_gas(&mut self, ret_gas: Gas) { - self.erase_cost(ret_gas.remaining()); - } - - /// Consume revert gas limit. - #[cfg(feature = "optimism")] - #[inline] - pub fn consume_revert_gas( - &mut self, - is_optimism: bool, - is_deposit: bool, - is_regolith: bool, - ret_gas: Gas, - ) { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (revert path): - // - Deposit transactions (all) report the gas limit as the amount of gas - // used on failure. No refunds. - // - Regular transactions receive a refund on remaining gas as normal. - // - Regolith (revert path): - // - Deposit transactions (all) report the actual gas used as the amount of - // gas used on failure. Refunds on remaining gas enabled. - // - Regular transactions receive a refund on remaining gas as normal. - if is_optimism && (!is_deposit || is_regolith) { - self.erase_cost(ret_gas.remaining()); - } - } - - /// Consumes the remaining gas. - #[cfg(not(feature = "optimism"))] - #[inline] - pub fn consume_gas(&mut self, ret_gas: Gas) { - self.erase_cost(ret_gas.remaining()); - self.record_refund(ret_gas.refunded()); - } - - /// Consume remaining gas. - #[cfg(feature = "optimism")] - #[inline] - pub fn consume_gas( - &mut self, - is_optimism: bool, - is_deposit: bool, - is_regolith: bool, - tx_system: Option, - gas_limit: u64, - ret_gas: Gas, - ) { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (success path): - // - Deposit transactions (non-system) report their gas limit as the usage. - // No refunds. - // - Deposit transactions (system) report 0 gas used. No refunds. - // - Regular transactions report gas usage as normal. - // - Regolith (success path): - // - Deposit transactions (all) report their gas used as normal. Refunds - // enabled. - // - Regular transactions report their gas used as normal. - if is_optimism && (!is_deposit || is_regolith) { - // For regular transactions prior to Regolith and all transactions after - // Regolith, gas is reported as normal. - self.erase_cost(ret_gas.remaining()); - self.record_refund(ret_gas.refunded()); - } else if is_deposit && tx_system.unwrap_or(false) { - // System transactions were a special type of deposit transaction in - // the Bedrock hardfork that did not incur any gas costs. - self.erase_cost(gas_limit); - } - } - /// used in memory_resize! macro to record gas used for memory expansion. #[inline] pub fn record_memory(&mut self, gas_memory: u64) -> bool { @@ -195,122 +116,3 @@ impl Gas { self.record_refund(refund); } } - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(not(feature = "optimism"))] - #[test] - fn test_consume_gas() { - let mut gas = Gas::new(100); - gas.record_cost(50); - assert_eq!(gas.remaining(), 50); - assert_eq!(gas.used, 50); - assert_eq!(gas.all_used_gas, 50); - - // Consume the revert gas - gas.consume_gas(Gas::new(50)); - assert_eq!(gas, Gas::new(100)); - } - - #[cfg(not(feature = "optimism"))] - #[test] - fn test_consume_gas_with_refund() { - let mut gas = Gas::new(100); - gas.record_cost(50); - assert_eq!(gas.remaining(), 50); - assert_eq!(gas.used, 50); - assert_eq!(gas.all_used_gas, 50); - - // Consume the revert gas - let mut ret_gas = Gas::new(50); - ret_gas.record_refund(50); - gas.consume_gas(ret_gas); - assert_eq!(gas.remaining(), 100); - assert_eq!(gas.used, 0); - assert_eq!(gas.all_used_gas, 0); - assert_eq!(gas.refunded, 50); - } - - #[cfg(not(feature = "optimism"))] - #[test] - fn test_revert_gas() { - let mut gas = Gas::new(100); - gas.record_cost(50); - assert_eq!(gas.remaining(), 50); - assert_eq!(gas.used, 50); - assert_eq!(gas.all_used_gas, 50); - - // Consume the revert gas - gas.consume_revert_gas(Gas::new(50)); - assert_eq!(gas.remaining(), 100); - assert_eq!(gas.used, 0); - assert_eq!(gas.all_used_gas, 0); - } - - #[cfg(feature = "optimism")] - #[test] - fn test_revert_gas() { - let mut gas = Gas::new(100); - gas.record_cost(50); - - gas.consume_revert_gas(true, false, false, Gas::new(50)); - assert_eq!(gas.remaining(), 100); - assert_eq!(gas.used, 0); - assert_eq!(gas.all_used_gas, 0); - - let mut gas = Gas::new(100); - gas.consume_revert_gas(false, false, false, Gas::new(50)); - } - - #[cfg(feature = "optimism")] - #[test] - fn test_revert_gas_non_optimism() { - let mut gas = Gas::new(100); - gas.consume_revert_gas(false, false, false, Gas::new(50)); - assert_eq!(gas.remaining(), 100); - } - - #[cfg(feature = "optimism")] - #[test] - fn test_consume_gas() { - let mut gas = Gas::new(100); - gas.record_cost(50); - - gas.consume_gas(true, true, true, None, 100, Gas::new(50)); - assert_eq!(gas.remaining(), 100); - assert_eq!(gas.used, 0); - assert_eq!(gas.all_used_gas, 0); - assert_eq!(gas.refunded, 0); - } - - #[cfg(feature = "optimism")] - #[test] - fn test_consume_gas_with_refund() { - let mut gas = Gas::new(100); - gas.record_cost(50); - - let mut ret_gas = Gas::new(50); - ret_gas.record_refund(50); - gas.consume_gas(true, true, true, None, 100, ret_gas); - assert_eq!(gas.remaining(), 100); - assert_eq!(gas.used, 0); - assert_eq!(gas.all_used_gas, 0); - assert_eq!(gas.refunded, 50); - } - - #[cfg(feature = "optimism")] - #[test] - fn test_consume_gas_sys_deposit_tx() { - let mut gas = Gas::new(100); - gas.record_cost(100); - gas.consume_gas(true, true, false, Some(true), 50, Gas::new(0)); - assert_eq!(gas.remaining(), 50); - assert_eq!(gas.used, 50); - assert_eq!(gas.all_used_gas, 50); - - gas.consume_gas(true, true, false, Some(true), 50, Gas::new(0)); - assert_eq!(gas, Gas::new(100)); - } -} diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index a430249f94..bcc2efb3a3 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1,7 +1,8 @@ +use crate::handlers; use crate::interpreter::{ - analysis::to_analysed, gas, instruction_result::SuccessOrHalt, return_ok, return_revert, - CallContext, CallInputs, CallScheme, Contract, CreateInputs, CreateScheme, Gas, Host, - InstructionResult, Interpreter, SelfDestructResult, Transfer, CALL_STACK_LIMIT, + analysis::to_analysed, gas, instruction_result::SuccessOrHalt, return_ok, CallContext, + CallInputs, CallScheme, Contract, CreateInputs, CreateScheme, Gas, Host, InstructionResult, + Interpreter, SelfDestructResult, Transfer, CALL_STACK_LIMIT, }; use crate::journaled_state::{is_precompile, JournalCheckpoint}; use crate::primitives::{ @@ -194,7 +195,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let tx_gas_limit = env.tx.gas_limit; #[cfg(feature = "optimism")] - let (tx_mint, tx_system, tx_l1_cost, is_deposit, l1_block_info) = { + let (tx_mint, is_deposit, tx_l1_cost, l1_block_info) = { let is_deposit = env.tx.optimism.source_hash.is_some(); let l1_block_info = @@ -213,13 +214,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact .unwrap_or(U256::ZERO) }); - ( - env.tx.optimism.mint, - env.tx.optimism.is_system_transaction, - tx_l1_cost, - is_deposit, - l1_block_info, - ) + (env.tx.optimism.mint, is_deposit, tx_l1_cost, l1_block_info) }; let initial_gas_spend = initial_tx_gas::( @@ -287,7 +282,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let transact_gas_limit = tx_gas_limit - initial_gas_spend; // call inner handling of call/create - let (exit_reason, ret_gas, output) = match self.data.env.tx.transact_to { + let (call_result, ret_gas, output) = match self.data.env.tx.transact_to { TransactTo::Call(address) => { // Nonce is already checked caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); @@ -324,39 +319,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact } }; - // Spend the gas limit. Gas is reimbursed when the tx returns successfully. - let mut gas = Gas::new(tx_gas_limit); - gas.record_cost(tx_gas_limit); - - if crate::USE_GAS { - match exit_reason { - return_ok!() => { - #[cfg(not(feature = "optimism"))] - gas.consume_gas(ret_gas); - #[cfg(feature = "optimism")] - gas.consume_gas( - self.data.env.cfg.optimism, - is_deposit, - GSPEC::enabled(SpecId::REGOLITH), - tx_system, - tx_gas_limit, - ret_gas, - ); - } - return_revert!() => { - #[cfg(not(feature = "optimism"))] - gas.consume_revert_gas(ret_gas); - #[cfg(feature = "optimism")] - gas.consume_revert_gas( - self.data.env.cfg.optimism, - is_deposit, - GSPEC::enabled(SpecId::REGOLITH), - ret_gas, - ); - } - _ => {} - } - } + let gas = handlers::handle_call_return::(self.env(), call_result, ret_gas); let (state, logs, gas_used, gas_refunded) = self.finalize::( &gas, @@ -364,7 +327,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact l1_block_info.as_ref(), ); - let result = match exit_reason.into() { + let result = match call_result.into() { SuccessOrHalt::Success(reason) => ExecutionResult::Success { reason, gas_used, @@ -403,7 +366,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact return Err(EVMError::Database(self.data.error.take().unwrap())); } SuccessOrHalt::InternalContinue => { - panic!("Internal return flags should remain internal {exit_reason:?}") + panic!("Internal return flags should remain internal {call_result:?}") } }; diff --git a/crates/revm/src/handlers.rs b/crates/revm/src/handlers.rs new file mode 100644 index 0000000000..ebba96f7fb --- /dev/null +++ b/crates/revm/src/handlers.rs @@ -0,0 +1,230 @@ +use crate::interpreter::{return_ok, return_revert, Gas, InstructionResult}; +use crate::primitives::{Env, Spec}; + +/// Handle output of the transaction +#[cfg(not(feature = "optimism"))] +pub fn handle_call_return( + env: &Env, + call_result: InstructionResult, + returned_gas: Gas, +) -> Gas { + let tx_gas_limit = env.tx.gas_limit; + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + let mut gas = Gas::new(tx_gas_limit); + gas.record_cost(tx_gas_limit); + + if crate::USE_GAS { + match call_result { + return_ok!() => { + gas.erase_cost(returned_gas.remaining()); + gas.record_refund(returned_gas.refunded()); + } + return_revert!() => { + gas.erase_cost(returned_gas.remaining()); + } + _ => {} + } + } + gas +} + +/// Handle output of the transaction +#[cfg(feature = "optimism")] +pub fn handle_call_return( + env: &Env, + call_result: InstructionResult, + returned_gas: Gas, +) -> Gas { + use crate::primitives::SpecId::REGOLITH; + let is_deposit = env.tx.optimism.source_hash.is_some(); + let is_optimism = env.cfg.optimism; + let tx_system = env.tx.optimism.is_system_transaction; + let tx_gas_limit = env.tx.gas_limit; + let is_regolith = SPEC::enabled(REGOLITH); + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + let mut gas = Gas::new(tx_gas_limit); + gas.record_cost(tx_gas_limit); + + if crate::USE_GAS { + match call_result { + return_ok!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + if is_optimism && (!is_deposit || is_regolith) { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(returned_gas.remaining()); + gas.record_refund(returned_gas.refunded()); + } else if is_deposit && tx_system.unwrap_or(false) { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(tx_gas_limit); + } + } + return_revert!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if is_optimism && (!is_deposit || is_regolith) { + gas.erase_cost(returned_gas.remaining()); + } + } + _ => {} + } + } + gas +} + +#[cfg(not(feature = "optimism"))] +#[cfg(test)] +mod tests { + use revm_interpreter::primitives::CancunSpec; + + use super::*; + + #[test] + fn test_consume_gas() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + + let gas = handle_call_return::(&env, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_with_refund() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + + let mut return_gas = Gas::new(90); + return_gas.record_refund(30); + + let gas = + handle_call_return::(&env, InstructionResult::Stop, return_gas.clone()); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 30); + + let gas = handle_call_return::(&env, InstructionResult::Revert, return_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_revert_gas() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + + let gas = handle_call_return::(&env, InstructionResult::Revert, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } +} + +#[cfg(feature = "optimism")] +#[cfg(test)] +mod tests { + use crate::primitives::{BedrockSpec, RegolithSpec}; + + use super::*; + use crate::primitives::B256; + + #[test] + fn test_revert_gas() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + env.cfg.optimism = true; + env.tx.optimism.source_hash = None; + + let gas = handle_call_return::(&env, InstructionResult::Revert, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_revert_gas_non_optimism() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + env.cfg.optimism = false; + env.tx.optimism.source_hash = None; + + let gas = handle_call_return::(&env, InstructionResult::Revert, Gas::new(90)); + // else branch takes all gas. + assert_eq!(gas.remaining(), 0); + assert_eq!(gas.spend(), 100); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + env.cfg.optimism = true; + env.tx.optimism.source_hash = Some(B256::zero()); + + let gas = handle_call_return::(&env, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_with_refund() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + env.cfg.optimism = true; + env.tx.optimism.source_hash = Some(B256::zero()); + + let mut ret_gas = Gas::new(90); + ret_gas.record_refund(20); + + let gas = + handle_call_return::(&env, InstructionResult::Stop, ret_gas.clone()); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 20); + + let gas = handle_call_return::(&env, InstructionResult::Revert, ret_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_sys_deposit_tx() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + env.cfg.optimism = true; + env.tx.optimism.source_hash = Some(B256::zero()); + + let gas = handle_call_return::(&env, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 0); + assert_eq!(gas.spend(), 100); + assert_eq!(gas.refunded(), 0); + } +} diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 7a16dd45e4..485dc325b5 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -7,6 +7,7 @@ extern crate alloc; pub mod db; mod evm; mod evm_impl; +pub mod handlers; mod inspector; mod journaled_state; From 5918f287a1ec0c904c958a618944bab571016d5c Mon Sep 17 00:00:00 2001 From: rakita Date: Tue, 26 Sep 2023 14:13:00 +0200 Subject: [PATCH 51/55] feat: Handler logic --- bins/revme/src/statetest/runner.rs | 6 + crates/primitives/src/env.rs | 4 - crates/primitives/src/result.rs | 6 +- crates/revm/src/evm_impl.rs | 217 +++++------------- crates/revm/src/handler.rs | 90 ++++++++ crates/revm/src/handler/mainnet.rs | 156 +++++++++++++ .../src/{handlers.rs => handler/optimism.rs} | 136 ++++++----- crates/revm/src/inspector/customprinter.rs | 3 +- crates/revm/src/inspector/gas.rs | 19 +- crates/revm/src/lib.rs | 4 +- 10 files changed, 398 insertions(+), 243 deletions(-) create mode 100644 crates/revm/src/handler.rs create mode 100644 crates/revm/src/handler/mainnet.rs rename crates/revm/src/{handlers.rs => handler/optimism.rs} (68%) diff --git a/bins/revme/src/statetest/runner.rs b/bins/revme/src/statetest/runner.rs index e8cccdc4c6..b709db7be1 100644 --- a/bins/revme/src/statetest/runner.rs +++ b/bins/revme/src/statetest/runner.rs @@ -60,6 +60,12 @@ fn skip_test(path: &Path) -> bool { // custom json parser. https://github.com/ethereum/tests/issues/971 | "ValueOverflow.json" + // TODO remove this after we merge branch to main. + | "NoSrcAccountCreate.json" + | "NoSrcAccount1559.json" + | "NoSrcAccountCreate1559.json" + | "NoSrcAccount.json" + // precompiles having storage is not possible | "RevertPrecompiledTouch_storage.json" | "RevertPrecompiledTouch.json" diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 0092744f84..acacd9866a 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -226,9 +226,6 @@ pub struct CfgEnv { /// If some it will effects EIP-170: Contract code size limit. Useful to increase this because of tests. /// By default it is 0x6000 (~25kb). pub limit_contract_code_size: Option, - /// Disables the coinbase tip during the finalization of the transaction. This is useful for - /// rollups that redirect the tip to the sequencer. - pub disable_coinbase_tip: bool, /// A hard memory limit in bytes beyond which [Memory] cannot be resized. /// /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to @@ -350,7 +347,6 @@ impl Default for CfgEnv { spec_id: SpecId::LATEST, perf_analyse_created_bytecodes: AnalysisKind::default(), limit_contract_code_size: None, - disable_coinbase_tip: false, #[cfg(feature = "std")] kzg_settings: crate::kzg::EnvKzgSettings::Default, #[cfg(feature = "memory_limit")] diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs index 1355ca47df..53a9768b9b 100644 --- a/crates/primitives/src/result.rs +++ b/crates/primitives/src/result.rs @@ -4,7 +4,11 @@ use bytes::Bytes; use core::fmt; use ruint::aliases::U256; -pub type EVMResult = core::result::Result>; +/// Result of EVM execution. +pub type EVMResult = EVMResultGeneric; + +/// Generic result of EVM execution. Used to represent error and generic output. +pub type EVMResultGeneric = core::result::Result>; #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index bcc2efb3a3..1a289e1574 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -1,4 +1,4 @@ -use crate::handlers; +use crate::handler::Handler; use crate::interpreter::{ analysis::to_analysed, gas, instruction_result::SuccessOrHalt, return_ok, CallContext, CallInputs, CallScheme, Contract, CreateInputs, CreateScheme, Gas, Host, InstructionResult, @@ -6,24 +6,21 @@ use crate::interpreter::{ }; use crate::journaled_state::{is_precompile, JournalCheckpoint}; use crate::primitives::{ - create2_address, create_address, keccak256, Account, AnalysisKind, Bytecode, Bytes, EVMError, - EVMResult, Env, ExecutionResult, HashMap, InvalidTransaction, Log, Output, ResultAndState, - Spec, + create2_address, create_address, keccak256, AnalysisKind, Bytecode, Bytes, EVMError, EVMResult, + Env, ExecutionResult, InvalidTransaction, Log, Output, ResultAndState, Spec, SpecId::{self, *}, TransactTo, B160, B256, U256, }; use crate::{db::Database, journaled_state::JournaledState, precompile, Inspector}; use alloc::boxed::Box; use alloc::vec::Vec; -use core::{cmp::min, marker::PhantomData}; +use core::marker::PhantomData; use revm_interpreter::gas::initial_tx_gas; use revm_interpreter::MAX_CODE_SIZE; use revm_precompile::{Precompile, Precompiles}; #[cfg(feature = "optimism")] use crate::optimism; -#[cfg(feature = "optimism")] -use core::ops::Mul; pub struct EVMData<'a, DB: Database> { pub env: &'a mut Env, @@ -31,11 +28,15 @@ pub struct EVMData<'a, DB: Database> { pub db: &'a mut DB, pub error: Option, pub precompiles: Precompiles, + /// Used as temporary value holder to store L1 block info. + #[cfg(feature = "optimism")] + pub l1_block_info: Option, } pub struct EVMImpl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> { data: EVMData<'a, DB>, inspector: &'a mut dyn Inspector, + handler: Handler, _phantomdata: PhantomData, } @@ -80,24 +81,25 @@ pub trait Transact { } } -impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, INSPECT> { +impl<'a, DB: Database> EVMData<'a, DB> { /// Load access list for berlin hardfork. /// /// Loading of accounts/storages is needed to make them hot. #[inline] fn load_access_list(&mut self) -> Result<(), EVMError> { - for (address, slots) in self.data.env.tx.access_list.iter() { - self.data - .journaled_state - .initial_account_load(*address, slots, self.data.db) + for (address, slots) in self.env.tx.access_list.iter() { + self.journaled_state + .initial_account_load(*address, slots, self.db) .map_err(EVMError::Database)?; } Ok(()) } +} +#[cfg(feature = "optimism")] +impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, INSPECT> { /// If the transaction is not a deposit transaction, subtract the L1 data fee from the /// caller's balance directly after minting the requested amount of ETH. - #[cfg(feature = "optimism")] fn remove_l1_cost( is_deposit: bool, tx_caller: B160, @@ -132,7 +134,6 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, /// If the transaction is a deposit with a `mint` value, add the mint value /// in wei to the caller's balance. This should be persisted to the database /// prior to the rest of execution. - #[cfg(feature = "optimism")] fn commit_mint_value( tx_caller: B160, tx_mint: Option, @@ -195,7 +196,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact let tx_gas_limit = env.tx.gas_limit; #[cfg(feature = "optimism")] - let (tx_mint, is_deposit, tx_l1_cost, l1_block_info) = { + let tx_l1_cost = { let is_deposit = env.tx.optimism.source_hash.is_some(); let l1_block_info = @@ -213,8 +214,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact }) .unwrap_or(U256::ZERO) }); + // storage l1 block info for later use. + self.data.l1_block_info = l1_block_info; - (env.tx.optimism.mint, is_deposit, tx_l1_cost, l1_block_info) + // + let Some(tx_l1_cost) = tx_l1_cost else { + panic!("[OPTIMISM] L1 Block Info could not be loaded from the DB.") + }; + + tx_l1_cost }; let initial_gas_spend = initial_tx_gas::( @@ -232,9 +240,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact .map_err(EVMError::Database)?; } - self.load_access_list()?; - // Without this line, the borrow checker complains that `self` is borrowed mutable above. - let env = &self.data.env; + self.data.load_access_list()?; // load acc let journal = &mut self.data.journaled_state; @@ -243,14 +249,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact if self.data.env.cfg.optimism { EVMImpl::::commit_mint_value( tx_caller, - tx_mint, + self.data.env.tx.optimism.mint, self.data.db, journal, )?; - let Some(tx_l1_cost) = tx_l1_cost else { - panic!("[OPTIMISM] L1 Block Info could not be loaded from the DB.") - }; + let is_deposit = self.data.env.tx.optimism.source_hash.is_some(); EVMImpl::::remove_l1_cost( is_deposit, tx_caller, @@ -266,11 +270,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // Subtract gas costs from the caller's account. // We need to saturate the gas cost to prevent underflow in case that `disable_balance_check` is enabled. - let mut gas_cost = U256::from(tx_gas_limit).saturating_mul(env.effective_gas_price()); + let mut gas_cost = + U256::from(tx_gas_limit).saturating_mul(self.data.env.effective_gas_price()); // EIP-4844 if GSPEC::enabled(CANCUN) { - let data_fee = env.calc_data_fee().expect("already checked"); + let data_fee = self.data.env.calc_data_fee().expect("already checked"); gas_cost = gas_cost.saturating_add(U256::from(data_fee)); } @@ -319,24 +324,36 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact } }; - let gas = handlers::handle_call_return::(self.env(), call_result, ret_gas); + let handler = &self.handler; + let data = &mut self.data; - let (state, logs, gas_used, gas_refunded) = self.finalize::( - &gas, - #[cfg(feature = "optimism")] - l1_block_info.as_ref(), - ); + // handle output of call/create calls. + let gas = handler.call_return(data.env, call_result, ret_gas); + + let gas_refunded = handler.calculate_gas_refund(data.env, &gas); + + // Reimburse the caller + handler.reimburse_caller(data, &gas, gas_refunded)?; + + // Reward beneficiary + handler.reward_beneficiary(data, &gas, gas_refunded)?; + + // used gas with refund calculated. + let final_gas_used = gas.spend() - gas_refunded; + + // reset journal and return present state. + let (state, logs) = self.data.journaled_state.finalize(); let result = match call_result.into() { SuccessOrHalt::Success(reason) => ExecutionResult::Success { reason, - gas_used, + gas_used: final_gas_used, gas_refunded, logs, output, }, SuccessOrHalt::Revert => ExecutionResult::Revert { - gas_used, + gas_used: final_gas_used, output: match output { Output::Call(return_value) => return_value, Output::Create(return_value, _) => return_value, @@ -348,6 +365,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact // the transaction halts. #[cfg(feature = "optimism")] { + let is_deposit = self.data.env.tx.optimism.source_hash.is_some(); let is_creation = matches!(output, Output::Create(_, _)); let regolith_enabled = GSPEC::enabled(SpecId::REGOLITH); let optimism_regolith = self.data.env.cfg.optimism && regolith_enabled; @@ -360,7 +378,10 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact acc.info.nonce = acc.info.nonce.checked_add(1).unwrap_or(u64::MAX); } } - ExecutionResult::Halt { reason, gas_used } + ExecutionResult::Halt { + reason, + gas_used: final_gas_used, + } } SuccessOrHalt::FatalExternalError => { return Err(EVMError::Database(self.data.error.take().unwrap())); @@ -393,137 +414,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, db, error: None, precompiles, + #[cfg(feature = "optimism")] + l1_block_info: None, }, inspector, + handler: Handler::mainnet::(), _phantomdata: PhantomData {}, } } - fn finalize( - &mut self, - gas: &Gas, - #[cfg(feature = "optimism")] l1_block_info: Option<&optimism::L1BlockInfo>, - ) -> (HashMap, Vec, u64, u64) { - let caller = self.data.env.tx.caller; - let coinbase = self.data.env.block.coinbase; - let (gas_used, gas_refunded) = if crate::USE_GAS { - let effective_gas_price = self.data.env.effective_gas_price(); - let basefee = self.data.env.block.basefee; - - let is_gas_refund_disabled = self.data.env.cfg.is_gas_refund_disabled(); - - #[cfg(feature = "optimism")] - let is_deposit = - self.data.env.cfg.optimism && self.data.env.tx.optimism.source_hash.is_some(); - - // Prior to Regolith, deposit transactions did not receive gas refunds. - #[cfg(feature = "optimism")] - let is_gas_refund_disabled = is_gas_refund_disabled - || (self.data.env.cfg.optimism && is_deposit && !SPEC::enabled(SpecId::REGOLITH)); - - let gas_refunded = if is_gas_refund_disabled { - 0 - } else { - // EIP-3529: Reduction in refunds - let max_refund_quotient = if SPEC::enabled(LONDON) { 5 } else { 2 }; - min(gas.refunded() as u64, gas.spend() / max_refund_quotient) - }; - - // return balance of not spend gas. - let Ok((caller_account, _)) = - self.data.journaled_state.load_account(caller, self.data.db) - else { - panic!("caller account not found"); - }; - - caller_account.info.balance = caller_account - .info - .balance - .saturating_add(effective_gas_price * U256::from(gas.remaining() + gas_refunded)); - - let disable_coinbase_tip = self.data.env.cfg.disable_coinbase_tip; - - // All deposit transactions skip the coinbase tip in favor of paying the - // various fee vaults. - #[cfg(feature = "optimism")] - let disable_coinbase_tip = - disable_coinbase_tip || (self.data.env.cfg.optimism && is_deposit); - - // transfer fee to coinbase/beneficiary. - if !disable_coinbase_tip { - // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. - let coinbase_gas_price = if SPEC::enabled(LONDON) { - effective_gas_price.saturating_sub(basefee) - } else { - effective_gas_price - }; - - let Ok((coinbase_account, _)) = self - .data - .journaled_state - .load_account(coinbase, self.data.db) - else { - panic!("coinbase account not found"); - }; - coinbase_account.mark_touch(); - coinbase_account.info.balance = coinbase_account - .info - .balance - .saturating_add(coinbase_gas_price * U256::from(gas.spend() - gas_refunded)); - } - - #[cfg(feature = "optimism")] - if self.data.env.cfg.optimism && !is_deposit { - // If the transaction is not a deposit transaction, fees are paid out - // to both the Base Fee Vault as well as the L1 Fee Vault. - let Some(l1_block_info) = l1_block_info else { - panic!("[OPTIMISM] Failed to load L1 block information."); - }; - - let Some(enveloped_tx) = &self.data.env.tx.optimism.enveloped_tx else { - panic!("[OPTIMISM] Failed to load enveloped transaction."); - }; - - let l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx, is_deposit); - - // Send the L1 cost of the transaction to the L1 Fee Vault. - let Ok((l1_fee_vault_account, _)) = self - .data - .journaled_state - .load_account(optimism::L1_FEE_RECIPIENT, self.data.db) - else { - panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); - }; - l1_fee_vault_account.mark_touch(); - l1_fee_vault_account.info.balance += l1_cost; - - // Send the base fee of the transaction to the Base Fee Vault. - let Ok((base_fee_vault_account, _)) = self - .data - .journaled_state - .load_account(optimism::BASE_FEE_RECIPIENT, self.data.db) - else { - panic!("[OPTIMISM] Failed to load Base Fee Vault account"); - }; - base_fee_vault_account.mark_touch(); - base_fee_vault_account.info.balance += - l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); - } - - (gas.spend() - gas_refunded, gas_refunded) - } else { - // touch coinbase - let _ = self - .data - .journaled_state - .load_account(coinbase, self.data.db); - self.data.journaled_state.touch(&coinbase); - (0, 0) - }; - let (new_state, logs) = self.data.journaled_state.finalize(); - (new_state, logs, gas_used, gas_refunded) - } - #[inline(never)] fn prepare_create(&mut self, inputs: &CreateInputs) -> Result { let gas = Gas::new(inputs.gas_limit); diff --git a/crates/revm/src/handler.rs b/crates/revm/src/handler.rs new file mode 100644 index 0000000000..9a5e2f5b2f --- /dev/null +++ b/crates/revm/src/handler.rs @@ -0,0 +1,90 @@ +pub mod mainnet; +#[cfg(feature = "optimism")] +pub mod optimism; + +use revm_interpreter::primitives::db::Database; +use revm_interpreter::primitives::{EVMError, EVMResultGeneric}; + +use crate::interpreter::{Gas, InstructionResult}; +use crate::primitives::{Env, Spec}; +use crate::EVMData; + +/// Handle call return and return final gas value. +type CallReturnHandle = fn(&Env, InstructionResult, Gas) -> Gas; + +/// Reimburse the caller with ethereum it didn't spent. +type ReimburseCallerHandle = + fn(&mut EVMData<'_, DB>, &Gas, u64) -> EVMResultGeneric<(), ::Error>; + +/// Reward beneficiary with transaction rewards. +type RewardBeneficiaryHandle = ReimburseCallerHandle; + +/// Calculate gas refund for transaction. +type CalculateGasRefundHandle = fn(&Env, &Gas) -> u64; + +/// Handler acts as a proxy and allow to define different behavior for different +/// sections of the code. This allows nice integration of different chains or +/// to disable some mainnet behavior. +pub struct Handler { + // Uses env, call resul and returned gas from the call to determine the gas + // that is returned from transaction execution.. + pub call_return: CallReturnHandle, + pub reimburse_caller: ReimburseCallerHandle, + pub reward_beneficiary: RewardBeneficiaryHandle, + pub calculate_gas_refund: CalculateGasRefundHandle, +} + +impl Handler { + /// Handler for the mainnet + pub fn mainnet() -> Self { + Self { + call_return: mainnet::handle_call_return::, + calculate_gas_refund: mainnet::calculate_gas_refund::, + reimburse_caller: mainnet::handle_reimburse_caller::, + reward_beneficiary: mainnet::reward_beneficiary::, + } + } + + /// Handler for the optimism + #[cfg(feature = "optimism")] + pub fn optimism() -> Self { + Self { + call_return: optimism::handle_call_return::, + // we reinburse caller the same was as in mainnet. + // Refund is calculated differently then mainnet. + reimburse_caller: mainnet::handle_reimburse_caller::, + calculate_gas_refund: optimism::calculate_gas_refund::, + reward_beneficiary: optimism::reward_beneficiary::, + } + } + + /// Handle call return, depending on instruction result gas will be reimbursed or not. + pub fn call_return(&self, env: &Env, call_result: InstructionResult, returned_gas: Gas) -> Gas { + (self.call_return)(env, call_result, returned_gas) + } + + /// Reimburse the caller with gas that were not spend. + pub fn reimburse_caller( + &self, + data: &mut EVMData<'_, DB>, + gas: &Gas, + gas_refund: u64, + ) -> Result<(), EVMError> { + (self.reimburse_caller)(data, gas, gas_refund) + } + + /// Calculate gas refund for transaction. Some chains have it disabled. + pub fn calculate_gas_refund(&self, env: &Env, gas: &Gas) -> u64 { + (self.calculate_gas_refund)(env, gas) + } + + /// Reward beneficiary + pub fn reward_beneficiary( + &self, + data: &mut EVMData<'_, DB>, + gas: &Gas, + gas_refund: u64, + ) -> Result<(), EVMError> { + (self.reward_beneficiary)(data, gas, gas_refund) + } +} diff --git a/crates/revm/src/handler/mainnet.rs b/crates/revm/src/handler/mainnet.rs new file mode 100644 index 0000000000..2e87f76100 --- /dev/null +++ b/crates/revm/src/handler/mainnet.rs @@ -0,0 +1,156 @@ +//! Mainnet related handlers. +use revm_interpreter::primitives::EVMError; + +use crate::{ + interpreter::{return_ok, return_revert, Gas, InstructionResult}, + primitives::{db::Database, Env, Spec, SpecId::LONDON, U256}, + EVMData, +}; + +/// Handle output of the transaction +pub fn handle_call_return( + env: &Env, + call_result: InstructionResult, + returned_gas: Gas, +) -> Gas { + let tx_gas_limit = env.tx.gas_limit; + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + let mut gas = Gas::new(tx_gas_limit); + gas.record_cost(tx_gas_limit); + + if crate::USE_GAS { + match call_result { + return_ok!() => { + gas.erase_cost(returned_gas.remaining()); + gas.record_refund(returned_gas.refunded()); + } + return_revert!() => { + gas.erase_cost(returned_gas.remaining()); + } + _ => {} + } + } + gas +} + +#[inline] +pub fn handle_reimburse_caller( + data: &mut EVMData<'_, DB>, + gas: &Gas, + gas_refund: u64, +) -> Result<(), EVMError> { + let _ = data; + let caller = data.env.tx.caller; + let effective_gas_price = data.env.effective_gas_price(); + + // return balance of not spend gas. + let (caller_account, _) = data + .journaled_state + .load_account(caller, data.db) + .map_err(EVMError::Database)?; + + caller_account.info.balance = caller_account + .info + .balance + .saturating_add(effective_gas_price * U256::from(gas.remaining() + gas_refund)); + + Ok(()) +} + +/// Reward beneficiary with gas fee. +#[inline] +pub fn reward_beneficiary( + data: &mut EVMData<'_, DB>, + gas: &Gas, + gas_refund: u64, +) -> Result<(), EVMError> { + let beneficiary = data.env.block.coinbase; + let effective_gas_price = data.env.effective_gas_price(); + + // transfer fee to coinbase/beneficiary. + // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. + let coinbase_gas_price = if SPEC::enabled(LONDON) { + effective_gas_price.saturating_sub(data.env.block.basefee) + } else { + effective_gas_price + }; + + let (coinbase_account, _) = data + .journaled_state + .load_account(beneficiary, data.db) + .map_err(EVMError::Database)?; + + coinbase_account.mark_touch(); + coinbase_account.info.balance = coinbase_account + .info + .balance + .saturating_add(coinbase_gas_price * U256::from(gas.spend() - gas_refund)); + + Ok(()) +} + +/// Calculate gas refund for transaction. +/// +/// If config is set to disable gas refund, it will return 0. +/// +/// If spec is set to london, it will decrease the maximum refund amount to 5th part of +/// gas spend. (Before london it was 2th part of gas spend) +#[inline] +pub fn calculate_gas_refund(env: &Env, gas: &Gas) -> u64 { + if env.cfg.is_gas_refund_disabled() { + 0 + } else { + // EIP-3529: Reduction in refunds + let max_refund_quotient = if SPEC::enabled(LONDON) { 5 } else { 2 }; + (gas.refunded() as u64).min(gas.spend() / max_refund_quotient) + } +} + +#[cfg(test)] +mod tests { + use revm_interpreter::primitives::CancunSpec; + + use super::*; + + #[test] + fn test_consume_gas() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + + let gas = handle_call_return::(&env, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_with_refund() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + + let mut return_gas = Gas::new(90); + return_gas.record_refund(30); + + let gas = + handle_call_return::(&env, InstructionResult::Stop, return_gas.clone()); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 30); + + let gas = handle_call_return::(&env, InstructionResult::Revert, return_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_revert_gas() { + let mut env = Env::default(); + env.tx.gas_limit = 100; + + let gas = handle_call_return::(&env, InstructionResult::Revert, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spend(), 10); + assert_eq!(gas.refunded(), 0); + } +} diff --git a/crates/revm/src/handlers.rs b/crates/revm/src/handler/optimism.rs similarity index 68% rename from crates/revm/src/handlers.rs rename to crates/revm/src/handler/optimism.rs index ebba96f7fb..b64d18edab 100644 --- a/crates/revm/src/handlers.rs +++ b/crates/revm/src/handler/optimism.rs @@ -1,32 +1,14 @@ -use crate::interpreter::{return_ok, return_revert, Gas, InstructionResult}; -use crate::primitives::{Env, Spec}; +//! Handler related to Optimism chain -/// Handle output of the transaction -#[cfg(not(feature = "optimism"))] -pub fn handle_call_return( - env: &Env, - call_result: InstructionResult, - returned_gas: Gas, -) -> Gas { - let tx_gas_limit = env.tx.gas_limit; - // Spend the gas limit. Gas is reimbursed when the tx returns successfully. - let mut gas = Gas::new(tx_gas_limit); - gas.record_cost(tx_gas_limit); +use core::ops::Mul; - if crate::USE_GAS { - match call_result { - return_ok!() => { - gas.erase_cost(returned_gas.remaining()); - gas.record_refund(returned_gas.refunded()); - } - return_revert!() => { - gas.erase_cost(returned_gas.remaining()); - } - _ => {} - } - } - gas -} +use super::mainnet; +use crate::{ + interpreter::{return_ok, return_revert, Gas, InstructionResult}, + optimism, + primitives::{db::Database, EVMError, Env, Spec, SpecId::REGOLITH, U256}, + EVMData, +}; /// Handle output of the transaction #[cfg(feature = "optimism")] @@ -35,7 +17,6 @@ pub fn handle_call_return( call_result: InstructionResult, returned_gas: Gas, ) -> Gas { - use crate::primitives::SpecId::REGOLITH; let is_deposit = env.tx.optimism.source_hash.is_some(); let is_optimism = env.cfg.optimism; let tx_system = env.tx.optimism.is_system_transaction; @@ -95,54 +76,69 @@ pub fn handle_call_return( gas } -#[cfg(not(feature = "optimism"))] -#[cfg(test)] -mod tests { - use revm_interpreter::primitives::CancunSpec; - - use super::*; +#[inline] +pub fn calculate_gas_refund(env: &Env, gas: &Gas) -> u64 { + let is_deposit = env.cfg.optimism && env.tx.optimism.source_hash.is_some(); - #[test] - fn test_consume_gas() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - - let gas = handle_call_return::(&env, InstructionResult::Stop, Gas::new(90)); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); - assert_eq!(gas.refunded(), 0); + // Prior to Regolith, deposit transactions did not receive gas refunds. + let is_gas_refund_disabled = env.cfg.optimism && is_deposit && !SPEC::enabled(REGOLITH); + if is_gas_refund_disabled { + 0 + } else { + mainnet::calculate_gas_refund::(env, gas) } +} - #[test] - fn test_consume_gas_with_refund() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - - let mut return_gas = Gas::new(90); - return_gas.record_refund(30); - - let gas = - handle_call_return::(&env, InstructionResult::Stop, return_gas.clone()); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); - assert_eq!(gas.refunded(), 30); - - let gas = handle_call_return::(&env, InstructionResult::Revert, return_gas); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); - assert_eq!(gas.refunded(), 0); +/// Reward beneficiary with gas fee. +#[inline] +pub fn reward_beneficiary( + data: &mut EVMData<'_, DB>, + gas: &Gas, + gas_refund: u64, +) -> Result<(), EVMError> { + let is_deposit = data.env.cfg.optimism && data.env.tx.optimism.source_hash.is_some(); + let disable_coinbase_tip = data.env.cfg.optimism && is_deposit; + + // transfer fee to coinbase/beneficiary. + if !disable_coinbase_tip { + mainnet::reward_beneficiary::(data, gas, gas_refund)?; } - #[test] - fn test_revert_gas() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - - let gas = handle_call_return::(&env, InstructionResult::Revert, Gas::new(90)); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); - assert_eq!(gas.refunded(), 0); + if data.env.cfg.optimism && !is_deposit { + // If the transaction is not a deposit transaction, fees are paid out + // to both the Base Fee Vault as well as the L1 Fee Vault. + let Some(l1_block_info) = data.l1_block_info.clone() else { + panic!("[OPTIMISM] Failed to load L1 block information."); + }; + + let Some(enveloped_tx) = &data.env.tx.optimism.enveloped_tx else { + panic!("[OPTIMISM] Failed to load enveloped transaction."); + }; + + let l1_cost = l1_block_info.calculate_tx_l1_cost::(enveloped_tx, is_deposit); + + // Send the L1 cost of the transaction to the L1 Fee Vault. + let Ok((l1_fee_vault_account, _)) = data + .journaled_state + .load_account(optimism::L1_FEE_RECIPIENT, data.db) + else { + panic!("[OPTIMISM] Failed to load L1 Fee Vault account"); + }; + l1_fee_vault_account.mark_touch(); + l1_fee_vault_account.info.balance += l1_cost; + + // Send the base fee of the transaction to the Base Fee Vault. + let Ok((base_fee_vault_account, _)) = data + .journaled_state + .load_account(optimism::BASE_FEE_RECIPIENT, data.db) + else { + panic!("[OPTIMISM] Failed to load Base Fee Vault account"); + }; + base_fee_vault_account.mark_touch(); + base_fee_vault_account.info.balance += + l1_block_info.l1_base_fee.mul(U256::from(gas.spend())); } + Ok(()) } #[cfg(feature = "optimism")] diff --git a/crates/revm/src/inspector/customprinter.rs b/crates/revm/src/inspector/customprinter.rs index ba69bdf249..c9ccf6ec03 100644 --- a/crates/revm/src/inspector/customprinter.rs +++ b/crates/revm/src/inspector/customprinter.rs @@ -126,8 +126,9 @@ impl Inspector for CustomPrintTracer { #[cfg(test)] mod test { - #[cfg(not(feature = "no_gas_measuring"))] #[test] + #[cfg(not(feature = "no_gas_measuring"))] + #[cfg(not(feature = "optimism"))] fn gas_calculation_underflow() { use crate::primitives::hex_literal; // https://github.com/bluealloy/revm/issues/277 diff --git a/crates/revm/src/inspector/gas.rs b/crates/revm/src/inspector/gas.rs index 28ccf87f28..24c8ff2e42 100644 --- a/crates/revm/src/inspector/gas.rs +++ b/crates/revm/src/inspector/gas.rs @@ -93,13 +93,8 @@ impl Inspector for GasInspector { #[cfg(test)] mod tests { - use crate::db::BenchmarkDB; - use crate::interpreter::{ - opcode, CallInputs, CreateInputs, Gas, InstructionResult, Interpreter, OpCode, - }; - use crate::primitives::{ - hex_literal::hex, Bytecode, Bytes, ResultAndState, TransactTo, B160, B256, - }; + use crate::interpreter::{CallInputs, CreateInputs, Gas, InstructionResult, Interpreter}; + use crate::primitives::{Bytes, B160, B256}; use crate::{inspectors::GasInspector, Database, EVMData, Inspector}; #[derive(Default, Debug)] @@ -209,7 +204,17 @@ mod tests { } #[test] + #[cfg(not(feature = "optimism"))] fn test_gas_inspector() { + use crate::db::BenchmarkDB; + use crate::interpreter::{ + opcode, CallInputs, CreateInputs, Gas, InstructionResult, Interpreter, OpCode, + }; + use crate::primitives::{ + hex_literal::hex, Bytecode, Bytes, ResultAndState, TransactTo, B160, B256, + }; + use crate::{inspectors::GasInspector, Database, EVMData, Inspector}; + let contract_data: Bytes = Bytes::from(vec![ opcode::PUSH1, 0x1, diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 485dc325b5..1742d34bdf 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -7,7 +7,7 @@ extern crate alloc; pub mod db; mod evm; mod evm_impl; -pub mod handlers; +pub mod handler; mod inspector; mod journaled_state; @@ -49,3 +49,5 @@ pub use inspector::Inspector; // export Optimism types, helpers, and constants #[cfg(feature = "optimism")] pub use optimism::{L1BlockInfo, BASE_FEE_RECIPIENT, L1_BLOCK_CONTRACT, L1_FEE_RECIPIENT}; + +pub use handler::Handler; From 8d97ea31445e7801834246c62ce4db64a159f02f Mon Sep 17 00:00:00 2001 From: rakita Date: Wed, 27 Sep 2023 12:01:20 +0200 Subject: [PATCH 52/55] remove USE_GAS from handlers --- .github/workflows/ci.yml | 3 + crates/revm/src/handler/mainnet.rs | 18 +++--- crates/revm/src/handler/optimism.rs | 87 ++++++++++++++--------------- 3 files changed, 53 insertions(+), 55 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b67c05895b..02d613b233 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,9 @@ jobs: cache-on-failure: true - name: cargo test + run: cargo test --workspace + + - name: cargo test all features run: cargo test --workspace --all-features - name: cargo check no_std diff --git a/crates/revm/src/handler/mainnet.rs b/crates/revm/src/handler/mainnet.rs index 2e87f76100..81f12fdb6c 100644 --- a/crates/revm/src/handler/mainnet.rs +++ b/crates/revm/src/handler/mainnet.rs @@ -18,17 +18,15 @@ pub fn handle_call_return( let mut gas = Gas::new(tx_gas_limit); gas.record_cost(tx_gas_limit); - if crate::USE_GAS { - match call_result { - return_ok!() => { - gas.erase_cost(returned_gas.remaining()); - gas.record_refund(returned_gas.refunded()); - } - return_revert!() => { - gas.erase_cost(returned_gas.remaining()); - } - _ => {} + match call_result { + return_ok!() => { + gas.erase_cost(returned_gas.remaining()); + gas.record_refund(returned_gas.refunded()); } + return_revert!() => { + gas.erase_cost(returned_gas.remaining()); + } + _ => {} } gas } diff --git a/crates/revm/src/handler/optimism.rs b/crates/revm/src/handler/optimism.rs index b64d18edab..bccab5608d 100644 --- a/crates/revm/src/handler/optimism.rs +++ b/crates/revm/src/handler/optimism.rs @@ -11,7 +11,6 @@ use crate::{ }; /// Handle output of the transaction -#[cfg(feature = "optimism")] pub fn handle_call_return( env: &Env, call_result: InstructionResult, @@ -26,52 +25,50 @@ pub fn handle_call_return( let mut gas = Gas::new(tx_gas_limit); gas.record_cost(tx_gas_limit); - if crate::USE_GAS { - match call_result { - return_ok!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (success path): - // - Deposit transactions (non-system) report their gas limit as the usage. - // No refunds. - // - Deposit transactions (system) report 0 gas used. No refunds. - // - Regular transactions report gas usage as normal. - // - Regolith (success path): - // - Deposit transactions (all) report their gas used as normal. Refunds - // enabled. - // - Regular transactions report their gas used as normal. - if is_optimism && (!is_deposit || is_regolith) { - // For regular transactions prior to Regolith and all transactions after - // Regolith, gas is reported as normal. - gas.erase_cost(returned_gas.remaining()); - gas.record_refund(returned_gas.refunded()); - } else if is_deposit && tx_system.unwrap_or(false) { - // System transactions were a special type of deposit transaction in - // the Bedrock hardfork that did not incur any gas costs. - gas.erase_cost(tx_gas_limit); - } + match call_result { + return_ok!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + if is_optimism && (!is_deposit || is_regolith) { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(returned_gas.remaining()); + gas.record_refund(returned_gas.refunded()); + } else if is_deposit && tx_system.unwrap_or(false) { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(tx_gas_limit); } - return_revert!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (revert path): - // - Deposit transactions (all) report the gas limit as the amount of gas - // used on failure. No refunds. - // - Regular transactions receive a refund on remaining gas as normal. - // - Regolith (revert path): - // - Deposit transactions (all) report the actual gas used as the amount of - // gas used on failure. Refunds on remaining gas enabled. - // - Regular transactions receive a refund on remaining gas as normal. - if is_optimism && (!is_deposit || is_regolith) { - gas.erase_cost(returned_gas.remaining()); - } + } + return_revert!() => { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if is_optimism && (!is_deposit || is_regolith) { + gas.erase_cost(returned_gas.remaining()); } - _ => {} } + _ => {} } gas } @@ -141,7 +138,7 @@ pub fn reward_beneficiary( Ok(()) } -#[cfg(feature = "optimism")] + #[cfg(test)] mod tests { use crate::primitives::{BedrockSpec, RegolithSpec}; From 5eacff1bd6ab65826868fa3d0055080bdd478ae0 Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 27 Sep 2023 07:35:49 -0400 Subject: [PATCH 53/55] Fix lints --- crates/revm/src/handler/optimism.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/revm/src/handler/optimism.rs b/crates/revm/src/handler/optimism.rs index bccab5608d..e71685f296 100644 --- a/crates/revm/src/handler/optimism.rs +++ b/crates/revm/src/handler/optimism.rs @@ -138,7 +138,6 @@ pub fn reward_beneficiary( Ok(()) } - #[cfg(test)] mod tests { use crate::primitives::{BedrockSpec, RegolithSpec}; From e63c990f535a67791461d605a6cc513536dda108 Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 27 Sep 2023 10:51:33 -0400 Subject: [PATCH 54/55] Update runner.rs Co-authored-by: rakita --- bins/revme/src/statetest/runner.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bins/revme/src/statetest/runner.rs b/bins/revme/src/statetest/runner.rs index e8a175edc2..476ad263e9 100644 --- a/bins/revme/src/statetest/runner.rs +++ b/bins/revme/src/statetest/runner.rs @@ -65,12 +65,6 @@ fn skip_test(path: &Path) -> bool { // custom json parser. https://github.com/ethereum/tests/issues/971 | "ValueOverflow.json" - // TODO remove this after we merge branch to main. - | "NoSrcAccountCreate.json" - | "NoSrcAccount1559.json" - | "NoSrcAccountCreate1559.json" - | "NoSrcAccount.json" - // precompiles having storage is not possible | "RevertPrecompiledTouch_storage.json" | "RevertPrecompiledTouch.json" From ec1f488bc9d18ab0b5f76958666f67e57c667c9a Mon Sep 17 00:00:00 2001 From: Andreas Bigger Date: Wed, 27 Sep 2023 12:07:23 -0400 Subject: [PATCH 55/55] Fix param mutability --- crates/primitives/src/env.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index 3a659264b3..8d883c7e54 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -706,7 +706,9 @@ mod tests { env.tx.optimism.source_hash = Some(B256::zero()); // Nonce and balance checks should be skipped for deposit transactions. - assert!(env.validate_tx_against_state(&Account::default()).is_ok()); + assert!(env + .validate_tx_against_state(&mut Account::default()) + .is_ok()); } #[test]